home *** CD-ROM | disk | FTP | other *** search
/ Windows News 2010 Summer - Disc 1 / WN_Ete2010_CD1.iso / Onglet5 / Weezo / Weezo setup.exe / {code_appDir} / www / includes / explorerFunctions.php < prev    next >
PHP Script  |  2010-05-19  |  149KB  |  3,647 lines

  1. <?php
  2. /**
  3.  * Set of functions used by browser scripts (explorer, photo, music)
  4.  *
  5.  * PHP version 5
  6.  *
  7.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  8.  * that is available through the world-wide-web at the following URI:
  9.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  10.  * the PHP License and are unable to obtain it through the web, please
  11.  * send a note to license@php.net so we can mail you a copy immediately.
  12.  *
  13.  * @category   NA
  14.  * @package    NA
  15.  * @author     Nicolas Bruley / Peer 2 World <contact@weezo.net>
  16.  * @copyright  2005-2009 Nicolas Bruley / Peer 2 World
  17.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18.  * @version    CVS: $Id:$
  19.  * @link       http://www.weezo.net
  20.  * @since      File available since Release 1.0.0
  21.  */
  22.  
  23. define('COMMENTS_FILE','comments.txt');
  24. define('MAX_COMMENT_LENGHT','2048');
  25. define('EDITABLE_FILES',';;txt;ini;xml;html;htm;cfg;css;res;php;php3;csv;js;bas;ctl;cls;frm;log;py;js;inc;c;h;cpp;bat;asp;mk;pas;rc;sql;dtd');
  26. define('SLIDESHOW_TIMER_CONTROL_NAME','slideShowInterval');
  27.  
  28. /**
  29.  * @desc display error page
  30.  *
  31.  * @param integer $errorCode : HTTP error code
  32.  */
  33. function  efDisplayError($errorCode){
  34.     require_once(INCLUDE_DIR.'initFunctions.php');
  35.     require_once(INCLUDE_DIR.'outputFunctions.php');
  36.  
  37.     switch ($errorCode){
  38.         case 403:
  39.             $message='403 Forbidden';
  40.             break;
  41.         case 404:
  42.         default:
  43.             $message='404 Not Found';
  44.             break;
  45.     }
  46.     header('HTTP/1.1 '.$message);
  47.  
  48.     cfLog($message .' - '.$_SERVER["REQUEST_URI"],LOG_DBG);
  49.     wSession_write_close();
  50.     outDisplayErrorPage($message .' - '.$_SERVER["REQUEST_URI"]);
  51.     exit();
  52. }
  53.  
  54.  
  55. /*
  56. ***************************************************************************************************************************
  57. * File information functions
  58. ***************************************************************************************************************************
  59. */
  60.  
  61.  
  62. /**
  63.  * @desc return (internal, based on mime_type array) file type (left part of mime type) depending on $file's extension
  64.  *
  65.  * @param string $file : file name (with or without path)
  66.  * @return string file type
  67.  */
  68. function efFileType($file){
  69.     if(!defined('MT_LOADED')) require(INCLUDE_DIR.'mime_type.php');
  70.     if((substr($file,1)==":/") || (strlen($file)==2 && substr($file,1,1)=="/")) return 'drive';
  71.     if(is_dir($file)) return 'folder';
  72.     if (($extension=strtolower(substr(strrchr($file,"."),1)))==false) return "unknown";
  73.     if(!isset($_ENV['weezoMime'][$extension])) return 'unknown';
  74.     return substr($_ENV['weezoMime'][$extension],0,strpos($_ENV['weezoMime'][$extension],"/"));
  75. }
  76.  
  77. /**
  78.  * @desc return (internal, based on mime_type array) full mime file type
  79.  *
  80.  * @param string $file : file name (with or without path)
  81.  * @return string mime type
  82.  */
  83. function efFileMimeType($file){
  84.     if(!defined('MT_LOADED')) require(INCLUDE_DIR.'mime_type.php');
  85.     if((strlen($file)==3 && substr($file,1,2)==":/") || (strlen($file)==2 && substr($file,1,1)=="/")) return false;
  86.     if(is_dir($file)) return false;
  87.     $extension=strtolower(substr(strrchr($file,"."),1));
  88.     if ($extension==false) return "text/plain";
  89.     return mimeType($extension);
  90. }
  91.  
  92. /**
  93.  * @desc return icon file name according to file's extension
  94.  *
  95.  * @param string $file : file name (with or without path)
  96.  * @param mixed $useExtracted: false to use weezo icons, true to use host system icons, 'exe' to extract icons only of exe/ico
  97.  * @param int $iconSize: size of extracted icon (16,32)
  98.  * @return string icon link
  99.  */
  100. function efIcon($file, $useExtracted=false,$iconSize=16){
  101.     $ext=cfFileExtension($file);
  102.  
  103.     if($useExtracted!=false && ($useExtracted===true||$ext=='exe'||$ext=='ico')){
  104.         static $extIcons=0;
  105.         if(!$extIcons) $extIcons=cfMGetVar('extensionIcons');
  106.         if ($ext=='exe'||$ext=='ico') return cfExtImage($file,$iconSize,$iconSize,true,0,array('icon'=>1));
  107.         // If not existing, generate
  108.         if(!isset($extIcons[$ext])){
  109.             efExtractIcon($file,cfAppDocRoot().'/gfx/ext/'.$ext.'.png',$iconSize);
  110.             $extIcons[$ext]=1;
  111.             cfMSetVar('extensionIcons',$extIcons);
  112.         }
  113.  
  114.         return '/gfx/ext/'.$ext.'.png';
  115.     }
  116.     switch($ext){
  117.         case 'm3u': case 'pls': return outIcon('fi/icoM3u');
  118.         case 'xls': case 'csv': case 'xlw': case 'xla': return outIcon('fi/icoXls');
  119.         case 'html': case 'htm': case 'xml': return outIcon('fi/icoXml');
  120.         case 'doc': case 'rtf': case 'dot': return outIcon('fi/icoDoc');
  121.         case 'ppt': case 'pps': return outIcon('fi/icoPpt');
  122.         case 'pdf': return outIcon('fi/icoPdf');
  123.         case 'zip': case 'rar': case 'ace': case 'gzip': case 'tar': case 'tgz': return outIcon('fi/icoZip');
  124.         case 'divx': case 'mkv': case 'wmv': return outIcon('fi/icoVid'); break;
  125.         case 'nfo': case 'sub': case 'log': case 'ini': case 'srt': case 'sub': return outIcon('fi/icoText');
  126.         case 'flv': case 'swf': return outIcon('fi/icoFlv');
  127.         case 'torrent': return outIcon('fi/icoTorrent');
  128.         case 'rss': case 'opml': return outIcon('fi/icoRss');
  129.         case 'url': return outIcon('fi/icoUrl');
  130.     }
  131.     switch(efFileType($file)){
  132.         case 'drive': return outIcon('fi/driveHDD');
  133.         case 'folder': return outIcon('fi/folder');
  134.         case 'image': return outIcon('fi/icoImage');
  135.         case 'audio': return outIcon('fi/icoMus');
  136.         case 'text':return outIcon('fi/icoText');
  137.         case 'video':return outIcon('fi/icoVid');
  138.     }
  139.     if(!$ext) return outIcon('fi/icoBlank');
  140.     if(efFileType($file)=='application') return outIcon('fi/icoProg');
  141.     return outIcon('fi/icoU');
  142. }
  143.  
  144. /**
  145.  * Extract icon associated to a file to png format
  146.  *
  147.  * @param string $file
  148.  * @param string $dest: destination png file, false to return
  149.  * @param int $size: icon width & height
  150.  * @return png icon if $dest is false
  151.  */
  152. function efExtractIcon($file,$dest=false,$size=16,$options=false){
  153.     if($dest==false) $dest=cfAppTempDir().'/tmp_ext.png';
  154.     // Dirty workaround for png files embeded into .ico
  155.     if($options && isset($options['icoPngCheck']) && cfFileExtension($file)=='ico'){
  156.         $fp=@fopen($file,'rb');$l=@fread($fp,4);@fclose($fp);
  157.         if($l=='ëPNG'){
  158.             if($dest==cfAppTempDir().'/tmp_ext.png') return file_get_contents($file);
  159.             file_put_contents($dest,file_get_contents($file));
  160.             return true;
  161.         }
  162.     }
  163.     $res=customExtractIcon(str_replace('/','\\',$file),str_replace('/','\\',$dest),$size);
  164.     if($dest!=cfAppTempDir().'/tmp_ext.png') return true;
  165.     $result=@file_get_contents($dest);
  166.     @unlink($dest);
  167.     return $result;
  168. }
  169.  
  170. /**
  171.  * @desc Get Drive information
  172.  *
  173.  * @param string $driveName: drive letter
  174.  * @return array (property=>value)
  175.  */
  176. function efDriveInfo($driveName){
  177.     if(strlen($driveName)==2) $driveName.='/';
  178.     $driveName=strtoupper($driveName);
  179.     $d=array();
  180.     $d['name']=$driveName;
  181.     $d['completeFileName']=$driveName;
  182.     $d['freeSpace']=@disk_free_space($driveName);
  183.     $d['totalSpace']=@disk_total_space($driveName);
  184.     $d['type']='drive';
  185.     $d['subType']=customDriveType($driveName);
  186.     switch ($d['subType']){
  187.         case 'Fixed':
  188.             $d['volumeType']=cfUTF8Decode(cfCaption('explorerDriveFixed'));
  189.             $d['icon']=outIcon('fi/driveHDD');;
  190.             break;
  191.         case 'CDROM':
  192.             $d['volumeType']=cfUTF8Decode(cfCaption('explorerDriveCDRom'));
  193.             $d['icon']=outIcon('fi/driveCdrom');;
  194.             break;
  195.         case 'RamDisk':
  196.             $d['volumeType']=cfUTF8Decode(cfCaption('explorerDriveRamDisk'));
  197.             $d['icon']=outIcon('fi/driveRam');;
  198.             break;
  199.         case 'Remote':
  200.             $d['volumeType']=cfUTF8Decode(cfCaption('explorerDriveRemote'));
  201.             $d['icon']=outIcon('fi/driveNetwork');;
  202.             break;
  203.         case 'Removable':
  204.             if($driveName=='A:/' || $driveName=='B:/') {
  205.                 $d['volumeType']=cfUTF8Decode(cfCaption('explorerDriveFloppy'));
  206.                 $d['icon']=outIcon('fi/driveFloppy');;
  207.             }
  208.             else{
  209.                 $d['volumeType']=cfUTF8Decode(cfCaption('explorerDriveRemovable'));
  210.                 $d['icon']=outIcon('fi/driveRemovable');;
  211.             }
  212.             break;
  213.         case 'Unknown':
  214.             $d['volumeType']=cfUTF8Decode(cfCaption('explorerDriveUnknown'));
  215.             $d['icon']=outIcon('fi/driveHDD');;
  216.             break;
  217.     }
  218.     $d['fileSystem']=customDriveFileSystem($driveName);
  219.     $d['volumeName']=customDriveName($driveName);
  220.     $d['driveReady']=customDriveReady($driveName);
  221.     return $d;
  222. }
  223.  
  224. /**
  225.  * @desc Return audio file information based on id3 tag
  226.  *
  227.  * @param string $fileName: name (without path) of file to add (note : path is efCurrentDirectory)
  228.  * @param boolean $returnCaptionForEmptyFields: true to remplace empty fields by localized caption
  229.  * @param boolean $extendedAnalysis: true to merge all ID3 fields (120% slower, better results)
  230.  * @param array $options:
  231.  *             "vbrParsing": does a full analysis of mp3 to get exact track duration (slower)
  232.  *             "noCache": doesn't use / fill cache database
  233.  *
  234.  * @return array :
  235.  *                 bitrate
  236.  *                 bitrateMode
  237.  *                 channelMode
  238.  *                 playtime_seconds
  239.  *                 title
  240.  *                 artist
  241.  *                 album
  242.  *                 year
  243.  *                 genre
  244.  *                 track
  245.  *                 comment
  246.  *                 label : label generated from artist, album, track, title and filename
  247.  */
  248. function efGetAudioInfo($completeFilename,$returnCaptionForEmptyFields=true,$options=array()){
  249.     static $id3V2Tags=false; // Object used to parse mp3 files. Static is used not to recreate object each time.
  250.     static $genre=array(0=>'Blues',1=>'Classic Rock',2=>'Country',3=>'Dance',4=>'Disco',5=>'Funk',6=>'Grunge',7=>'Hip-Hop',8=>'Jazz',9=>'Metal',10=>'New Age',11=>'Oldies',12=>'Other',13=>'Pop',14=>'R&B',15=>'Rap',16=>'Reggae',17=>'Rock',18=>'Techno',19=>'Industrial',20=>'Alternative',21=>'Ska',22=>'Death Metal',23=>'Pranks',24=>'Soundtrack',25=>'Euro-Techno',26=>'Ambient',27=>'Trip-Hop',28=>'Vocal',29=>'Jazz+Funk',30=>'Fusion',31=>'Trance',32=>'Classical',33=>'Instrumental',34=>'Acid',35=>'House',36=>'Game',37=>'Sound Clip',38=>'Gospel',39=>'Noise',40=>'AlternRock',41=>'Bass',42=>'Soul',43=>'Punk',44=>'Space',45=>'Meditative',46=>'Instrumental Pop',47=>'Instrumental Rock',48=>'Ethnic',49=>'Gothic',50=>'Darkwave',51=>'Techno-Industrial',52=>'Electronic',53=>'Pop-Folk',54=>'Eurodance',55=>'Dream',56=>'Southern Rock',57=>'Comedy',58=>'Cult',59=>'Gangsta',60=>'Top 40',61=>'Christian Rap',62=>'Pop/Funk',63=>'Jungle',64=>'Native American',65=>'Cabaret',66=>'New Wave',67=>'Psychadelic',68=>'Rave',69=>'Showtunes',70=>'Trailer',71=>'Lo-Fi',72=>'Tribal',73=>'Acid Punk',74=>'Acid Jazz',75=>'Polka',76=>'Retro',77=>'Musical',78=>'Rock & Roll',79=>'Hard Rock',80=>'Folk',81=>'Folk-Rock',82=>'National Folk',83=>'Swing',84=>'Fast Fusion',85=>'Bebob',86=>'Latin',87=>'Revival',88=>'Celtic',89=>'Bluegrass',90=>'Avantgarde',91=>'Gothic Rock',92=>'Progressive Rock',93=>'Psychedelic Rock',94=>'Symphonic Rock',95=>'Slow Rock',96=>'Big Band',97=>'Chorus',98=>'Easy Listening',99=>'Acoustic',100=>'Humour',101=>'Speech',102=>'Chanson',103=>'Opera',104=>'Chamber Music',105=>'Sonata',106=>'Symphony',107=>'Booty Bass',108=>'Primus',109=>'Porn Groove',110=>'Satire',111=>'Slow Jam',112=>'Club',113=>'Tango',114=>'Samba',115=>'Folklore',116=>'Ballad',117=>'Power Ballad',118=>'Rhythmic Soul',119=>'Freestyle',120=>'Duet',121=>'Punk Rock',122=>'Drum Solo',123=>'A capella');
  251.     static $iso14496Conv=array('day'=>'year','alb'=>'album','nam'=>'title','art'=>'artist','gen'=>'genre','cmt'=>'comment','wrt'=>'composer','too'=>'encodedBy','cprt'=>'copyrightInfo');
  252.     static $cacheData=-1;
  253.     static $cacheRSF=0;
  254.  
  255.     if($options) $options=cfArrayValuesToKeys($options);
  256.  
  257.     // Seek in cache database for information
  258.     if($cacheData==-1) $cacheData=cfHGetVar('cacheAudioData');
  259.     if($cacheData && !isset($options['noCache'])){
  260.         if(!isset($_ENV['efGetAudioInfoCacheDB'])){
  261.             $_ENV['efGetAudioInfoCacheDB']=sqlite_open(cfAppDataDir().'/audioCacheV3.db');
  262.             $_ENV['efGetAudioInfoCache']='';
  263.         }
  264.         // Create db if needed
  265.         if(!(sqlite_single_query($_ENV['efGetAudioInfoCacheDB'], "SELECT name FROM sqlite_master WHERE type='table' AND name='tracks'")))
  266.         sqlite_query('CREATE TABLE tracks ('.
  267.         'completeFilename TEXT PRIMARY KEY, filemtime INTEGER, label TEXT, title TEXT, artist TEXT, '.
  268.         'album TEXT, track TEXT, year TEXT, genre TEXT, comment TEXT, length INTEGER, vbrParsing INTEGER, APIC INTEGER)',$_ENV['efGetAudioInfoCacheDB']);
  269.  
  270.         // Search for file in db
  271.         @list($id3)=sqlite_array_query('SELECT * from tracks WHERE completeFilename="'.$completeFilename.'" LIMIT 1',$_ENV['efGetAudioInfoCacheDB'],SQLITE_ASSOC);
  272.         if($id3){
  273.             // outdated info or not generated with requested vbr parsing
  274.             if($id3['filemtime']!=filemtime($completeFilename) || (isset($options['vbrParsing'])&&!$id3['vbrParsing']))
  275.             $_ENV['efGetAudioInfoCache'].='DELETE FROM tracks WHERE completeFilename="'.$completeFilename.'";';
  276.             // Found: return cache
  277.             else {
  278.                 if($returnCaptionForEmptyFields){
  279.                     if(!$id3['artist']) $id3['artist']=cfCaption('explorerAudioUnknownArtist');
  280.                     if(!$id3['album']) $id3['album']=cfCaption('explorerAudioUnknownAlbum');
  281.                 }
  282.                 return $id3;
  283.             }
  284.         }
  285.     }
  286.  
  287.     $id3=array('artist'=>false,'album'=>false,'track'=>false,'year'=>false,'genre'=>false,'length'=>0,'comment'=>false);
  288.  
  289.     switch (cfFileExtension($completeFilename)){
  290.         // WMA/WMV/ASF
  291.         case 'asf':
  292.         case 'wma':
  293.         case 'wmv':
  294.             require_once('ASF.php');
  295.             $asf=new ASF($completeFilename,array('base'=>'header'));
  296.  
  297.             if(isset($asf->header->contentDescription)) $id3['artist']=$asf->header->contentDescription->author;
  298.             if(isset($asf->header->contentDescription)) $id3['title']=$asf->header->contentDescription->title;
  299.             if(isset($asf->header->extendedContentDescription)) {
  300.                 $id3['length']=$asf->header->fileProperties->playDuration/10/1000;
  301.                 // Browse tags
  302.                 foreach ($asf->header->extendedContentDescription->descriptors as $key => $value) {
  303.                     // Convert to ID3 format
  304.                     if($key!='ID3' && $key!='WM/Picture') $value=cfUTF8Decode($value);
  305.                     if($key=='WM/TrackNumber') $id3['track']=$value;
  306.                     elseif($key=='WM/Track' && !$id3['track']) $id3['track']=$value;
  307.                     elseif ($value){
  308.                         if($key=='Title') $id3['title']=$value;
  309.                         elseif($key=='ID3'){}
  310.                         elseif ($key=='WM/Picture') $id3['APIC']='TRUE';
  311.                         elseif ($key=='WM/AlbumTitle') $id3['album']=$value;
  312.                         elseif ($key=='WM/AlbumArtist') $id3['band']=$value;
  313.                         elseif(substr($key,0,3)=='WM/') $id3[strtolower(substr($key,3,1)).substr($key,4)]=$value;
  314.                         else $id3[strtolower(substr($key,0,1)).substr($key,1)]=$value;
  315.                     }
  316.                 }
  317.             }
  318.             unset($asf);
  319.             break;
  320.  
  321.         // Misc mp4? formats
  322.         case '3gp': case '3gpp': case 'avc': case 'dcf': case 'm21': case 'm4a':
  323.         case 'm4b': case 'm4p': case 'm4v': case 'maf': case 'mj2': case 'mjp':
  324.         case 'mov': case 'mp4': case 'odf': case 'sdv': case 'qt': case 'aac':case 'aif':
  325.             require_once('ISO14496.php');
  326.             $isom=new ISO14496($completeFilename,array("base" => "moov.mvhd"));
  327.             if(isset($isom->moov->mvhd)) $id3['length']=floor(1000*($isom->moov->mvhd->duration/$isom->moov->mvhd->timescale));
  328.             $isom=new ISO14496($completeFilename,array("base" => "moov.udta.meta.ilst"));
  329.             if (isset($isom->moov->udta->meta->ilst)){
  330.                 foreach ($isom->moov->udta->meta->ilst->boxes as $name => $boxes)
  331.                 foreach ($boxes as $box){
  332.                     $name=strtolower((($name[0]=='⌐')?substr($name,1):$name));
  333.                     if(isset($iso14496Conv[$name])) $id3[$iso14496Conv[$name]]=cfUTF8Decode($box->data->value,true,false,false);
  334.                     // Track number
  335.                     elseif ($name=='trkn') {
  336.                         $id3['track']=substr($box->data->value,3);
  337.                         $pos=0;while ($pos+1<strlen($id3['track']) && !(substr($id3['track'],$pos,1)=="0" && substr($id3['track'],$pos+1,1)!="0")) $pos++;
  338.                         $id3['track']=(int)substr($id3['track'],0,$pos);
  339.                     }
  340.                     elseif ($name=='covr') $id3['APIC']='TRUE';
  341.                 }
  342.             }
  343.             unset($isom);
  344.             break;
  345.  
  346.         // OGG vorbis
  347.         case 'ogg':
  348.             if(!defined('MF_LOADED')) require(INCLUDE_DIR.'miscFunctions.php');
  349.             // Get FLAC metadata
  350.             $oggMetaData=new OGGMetaData($completeFilename);
  351.  
  352.             // If OK, use them
  353.             if(count($oggMetaData->tag))    $id3=$oggMetaData->tag+$id3;
  354.  
  355.             /*
  356.             if($fp=@fopen('ogg://'.$completeFilename,'r')){
  357.             if(!defined('MF_LOADED')) require(INCLUDE_DIR.'miscFunctions.php');
  358.  
  359.             $metadata = stream_get_meta_data($fp);
  360.             fclose($fp);
  361.             if(isset($metadata['wrapper_data'][0])){
  362.             $metadata=$metadata['wrapper_data'][0];
  363.             if(isset($metadata['bitrate_nominal']))
  364.             $id3['length']=8000000*filesize($completeFilename)/$metadata['bitrate_nominal'];
  365.             if(isset($metadata['comments'])) foreach ($metadata['comments'] as $item){
  366.             @list($tag,$value)=explode('=',$item,2);
  367.             if($value){
  368.             $tag=strtolower($tag);
  369.  
  370.             if($tag=='date') $id3['year']=$value;
  371.             elseif($tag=='tracknumber') $id3['track']=$value;
  372.             elseif(in_array($tag,id3V2Ext::$frames)) $id3[$tag]=cfUTF8Decode($value);
  373.             }
  374.             }
  375.             }
  376.             }
  377.             */
  378.             unset($oggMetaData);
  379.             break;
  380.             // FLAC
  381.         case 'flac':
  382.             if(!defined('MF_LOADED')) require(INCLUDE_DIR.'miscFunctions.php');
  383.             // Get FLAC metadata
  384.             $flacMetaData=new FLACMetaData($completeFilename);
  385.  
  386.             // If OK, use them
  387.             if(count($flacMetaData->tag))    $id3=$flacMetaData->tag+$id3;
  388.  
  389.             break;
  390.             // MPC: not supported
  391.         case 'mpc':
  392.             break;
  393.             // MP3
  394.         default:
  395.             if(!defined('MF_LOADED')) require(INCLUDE_DIR.'miscFunctions.php');
  396.             // Get ID3V2 tags
  397.             if(!$id3V2Tags)    $id3V2Tags=new id3V2Ext($completeFilename,false,true,isset($options['vbrParsing']));
  398.             else $id3V2Tags->parseFile($completeFilename,false,true,isset($options['vbrParsing']));
  399.  
  400.             // If OK, use them
  401.             if(count($id3V2Tags->tag)>3) $id3=$id3V2Tags->tag+$id3;
  402.             // Else, use php_id3 to get ID3V1 tags
  403.             else{
  404.                 $id3=array_merge($id3,efGetAudioInfoUnsetEmptyValues(@id3_get_tag($completeFilename, ID3_BEST)));
  405.  
  406.                 // UTF8/16 decode
  407.                 foreach ($id3 as $key=>$value) {
  408.                     if(substr($value,0,2)==' ■') $id3[$key]=cfCodePageDecode(substr($value,2),'UTF-16');
  409.                     elseif(substr($value,0,2)=='■ ') $id3[$key]=cfUTF8Decode(substr($value,2),true,false,false);
  410.                 }
  411.  
  412.                 // Clear null caracters
  413.                 foreach ($id3 as $key=>$value) $id3[$key]=str_replace(chr(0),'',$value);
  414.  
  415.                 // Mix with $id3V2 tags
  416.                 foreach ($id3V2Tags->tag as $k=>$v) if($v!==false) $id3[$k]=$v;
  417.             }
  418.             // Genre
  419.             if(isset($id3['genre']) && is_numeric($id3['genre'])){
  420.                 if(isset($genre[(int)$id3['genre']])) $id3['genre']=$genre[$id3['genre']];
  421.             }
  422.             //unset($id3V2Tags);
  423.             break;
  424.     }
  425.  
  426.  
  427.     // Use album artist instead of artist
  428.     if(isset($id3['band']) && $id3['band']) {
  429.         // Move artist in original artist
  430.         if(!isset($id3['originalArtist'])) $id3['originalArtist']=$id3['artist'];
  431.         $id3['artist']=$id3['band'];
  432.     }
  433.  
  434.     // Clean strings (used by files/music explorers)
  435.     if($returnCaptionForEmptyFields){
  436.         if(!$id3['artist']) {$id3['artist']=cfCaption('explorerAudioUnknownArtist'); $filledArtist=true;}
  437.         if(!$id3['album']) {$id3['album']=cfCaption('explorerAudioUnknownAlbum'); $filledAlbum=true;}
  438.  
  439.         $id3['artist']=str_replace('"',"'",$id3['artist']);
  440.         $id3['album']=str_replace('"',"'",$id3['album']);
  441.         if(isset($id3['title'])) $id3['title']=str_replace('"',"'",$id3['title']);
  442.     }
  443.  
  444.     // Generate song's label
  445.     if(isset($id3['title'])){
  446.         if($id3['artist'])    $mdArtist=$id3['artist']; else $mdArtist=' '.cfCaption('explorerAudioUnknownArtist');
  447.         if($id3['album'])    $mdAlbum=$id3['album']; else $mdAlbum=cfCaption('explorerAudioUnknownAlbum');
  448.         if($id3['track'])    $id3['label']= $mdArtist.' - '.$mdAlbum.' - '.$id3['track'].' - '.$id3['title'];
  449.         else                         $id3['label']= $mdArtist.' - '.$mdAlbum.' - '.$id3['title'];
  450.     }
  451.     else {
  452.         $id3['label']=cfFileWithoutExtension(basename($completeFilename));
  453.         $id3['title']=cfFileWithoutExtension(basename($completeFilename));
  454.     }
  455.     // Insert data into cache
  456.     if($cacheData && !isset($options['noCache'])){
  457.         if(isset($filledArtist)) $id3['artist']='';    if(isset($filledAlbum)) $id3['album']='';
  458.         foreach ($id3 as $k=>$v) if(strpos($v,'"')) $id3[$k]=str_replace('"',"'",$v);
  459.         // Register function that will commit insert and delete queries
  460.         if(!$cacheRSF) {$cacheRSF=1;register_shutdown_function('efGetAudioInfoCommitCache');}
  461.         // Concatenate request to queue
  462.         $_ENV["efGetAudioInfoCache"].="INSERT INTO tracks VALUES ('".sqlite_escape_string($completeFilename)."', ".@filemtime($completeFilename).", '".
  463.         sqlite_escape_string($id3["label"])."', '".sqlite_escape_string($id3["title"])."', '".sqlite_escape_string($id3["artist"])."', '".
  464.         sqlite_escape_string($id3["album"])."', '".sqlite_escape_string($id3["track"])."', '".sqlite_escape_string($id3["year"])."', '".
  465.         sqlite_escape_string($id3["genre"])."', '".sqlite_escape_string($id3["comment"])."', ".$id3["length"].", ".
  466.         ((int)(isset($options["vbrParsing"]))).", ".((isset($id3["APIC"]))?'1':'0').");";
  467.     }
  468.     return $id3;
  469. }
  470. function efGetAudioInfoUnsetEmptyValues($arr){
  471.     if(!is_array($arr)) return array();
  472.     foreach ($arr as $key=>$value) if($value==='') unset($arr[$key]);
  473.     return $arr;
  474. }
  475.  
  476. /**
  477.  * @desc Commit changes to audio info cache DB
  478.  *
  479.  */
  480. function efGetAudioInfoCommitCache(){
  481.     @sqlite_query('BEGIN TRANSACTION;'.$_ENV['efGetAudioInfoCache'].'COMMIT;',$_ENV['efGetAudioInfoCacheDB']);
  482.     sqlite_close($_ENV['efGetAudioInfoCacheDB']);
  483. }
  484.  
  485. /**
  486.  * @desc compute number of files and total size of a directory and subdirectories
  487.  *
  488.  * @param string : $completeFilename : path of upper dir
  489.  * @return array : nb of files, total size
  490.  */
  491. function efDirGetFilesSize($completeFilename){
  492.     $nb=0;$size=0;
  493.     if($handle=@opendir($completeFilename)){
  494.         while (false !== ($file = readdir($handle))) if($file!='.' && $file!='..'){
  495.             if(is_file($completeFilename.'/'.$file)){
  496.                 if(!cfFileRights($completeFilename,'download',false)) continue;
  497.                 $nb++;
  498.                 $size+=cfFileSize($completeFilename.'/'.$file);
  499.             }
  500.             else{
  501.                 if(!cfFileRights($completeFilename,'state',false)) continue;
  502.                 list($nbD,$sizeD)=efDirGetFilesSize($completeFilename.'/'.$file);
  503.                 $nb+=$nbD;
  504.                 $size+=$sizeD;
  505.             }
  506.             cfPingUpdate(100); // Ping app
  507.         }
  508.     }
  509.     return array($nb,$size);
  510. }
  511.  
  512.  
  513. /*
  514. ***************************************************************************************************************************
  515. * Download functions
  516. ***************************************************************************************************************************
  517. */
  518.  
  519. /**
  520.  * @desc transforms a value into file size format (O/Ko/Mo/Go)
  521.  *
  522.  * @param string $file : file size (octets)
  523.  * @return string formated file size
  524.  */
  525. function efFileSizeFormat($fileSize){
  526.     if ($fileSize<1024) return efNumberFormat($fileSize, 0)."  B";
  527.     if ($fileSize<1024*1024) return efNumberFormat($fileSize/1024, 2)." KB";
  528.     if ($fileSize<1024*1024*1024) return efNumberFormat($fileSize/1024/1024, 2)." MB";
  529.     else return efNumberFormat($fileSize/1024/1024/1024,3)." GB";
  530. }
  531.  
  532. /**
  533.  * @desc read tokens in tokens file (transferTokens.txt)
  534.  *
  535.  * @return array : tokens
  536.  */
  537. function efTokensRead(){
  538.  
  539.     $removed=false;
  540.     $tokensFile=cfAppDataDir().'/transferTokens.txt';
  541.  
  542.     // Load from memory
  543.     if(!($tokenList=cfMGetVar('weezoTransferTokens'))){
  544.         if(!file_exists($tokensFile)) return array();
  545.         $tokenList=cfParse_ini_file($tokensFile,true,false);
  546.     }
  547.  
  548.     // Remove expired tokens
  549.     $removed=array();
  550.  
  551.     foreach ($tokenList as $key=>$value) if(!efTokenIsValid($value)) $removed[]=$key;
  552.  
  553.     if(count($removed)) {
  554.         foreach ($removed as $k) unset($tokenList[$k]);
  555.         cfWriteIniFile($tokenList,$tokensFile,true);
  556.     }
  557.     return $tokenList;
  558. }
  559.  
  560. /**
  561.  * @desc Save token array to file (replace file content, don't append !)
  562.  *
  563.  * @param array $tokenList : array of tokens
  564.  */
  565. function efTokensWrite($tokenList){
  566.     cfMSetVar('weezoTransferTokens',$tokenList);
  567.     cfWriteIniFile($tokenList,cfAppDataDir().'/transferTokens.txt',true);
  568. }
  569. /**
  570.  * @desc Check if a token is perempted or has reached its downloads limit
  571.  *
  572.  * @param array $token
  573.  * @return boolean
  574.  */
  575. function efTokenIsValid(&$token){
  576.     static $t=0;
  577.     static $dTL=0;
  578.     if($t==0){$t=time();$dTL=cfGGetVar('downloadTokenLifetime');}
  579.     if(!isset($token['type'])) return false;
  580.     if(isset($token['limitNbOriginal']) && isset($token['limitNb']) && $token['limitNb']<=0) return false;
  581.     if(isset($token['expiry']) && $token['expiry'] && time()>$token['expiry']) return false;
  582.     if($token['type']=='download' && (!isset($token['userId']) || ($dTL>0 && ($t-$token['creationTime'])>$dTL))) return false;
  583.     return true;
  584. }
  585.  
  586. /**
  587.  * @desc process finished download's token :
  588.  *         decrement limitNb or unset if necessary
  589.  *
  590.  * @param string $tokenId
  591.  */
  592. function efTokenDlFinished($tokenId){
  593.     $tokenList=efTokensRead();
  594.     if(isset($tokenList[$tokenId])){
  595.         if(!isset($tokenList[$tokenId]['limitNb']) || $tokenList[$tokenId]['limitNb']==1) unset($tokenList[$tokenId]);
  596.         else $tokenList[$tokenId]['limitNb']--;
  597.         efTokensWrite($tokenList);
  598.     }
  599. }
  600.  
  601. /**
  602.  * @desc closed session download resume
  603.  *         check download existence in token database
  604.  *
  605.  */
  606. function efResumeDownload($tokenId){
  607.     require_once(INCLUDE_DIR.'initFunctions.php');
  608.     if(substr($tokenId,0,7)=='dlToken') $tokenId=substr($tokenId,7);
  609.     // Load stored tokens and Check token existence
  610.     $tokenList=efTokensRead();
  611.     if(!$tokenList || !isset($tokenList[$tokenId])) {require_once(INCLUDE_DIR.'outputFunctions.php');outDisplayErrorPage(cfCaption('directLinkNotValid'));}
  612.  
  613.     // Check file existence
  614.     if(!file_exists($tokenList[$tokenId]['filename'])) efDisplayError(404);
  615.  
  616.     // Load user data (downloads only)
  617.     if($tokenList[$tokenId]['type']=='download'){
  618.         $userFiles=glob(cfAppDataDir().'/*.usr');
  619.         foreach ($userFiles as $value){
  620.             $userData=cfParse_ini_file($value, true);
  621.             if(isset($userData['id']) && $userData['id']==$tokenList[$tokenId]['userId']){
  622.                 $_SESSION['user']=$userData;
  623.                 $_SESSION['user']['id']=$tokenList[$tokenId]['userId'];
  624.                 break;
  625.             }
  626.         }
  627.         // If user not found
  628.         if(!isset($_SESSION['user'])) efDisplayError(403);
  629.     }
  630.     // Direct link
  631.     elseif ($tokenList[$tokenId]['type']=='directLink')    {
  632.         // Bittorrent transfer: send .torrent file to output
  633.         if(@$tokenList[$tokenId]['torrent']){
  634.             $metainfo=base64_decode($tokenList[$tokenId]['torrent']);
  635.             header('Content-Type: application/x-bittorrent');
  636.             header('Content-Disposition: attachment; filename="'.cfUTF8Encode(basename(cfFileWithoutExtension($tokenList[$tokenId]['filename']))).'.torrent"');
  637.             header('Content-Length: '.strlen($metainfo));
  638.             die($metainfo);
  639.         }
  640.     }
  641.     elseif ($tokenList[$tokenId]['type']=='publishDownload')    {}
  642.     // Else... error
  643.     else efDisplayError(403);
  644.  
  645.     // Start download
  646.  
  647.     // Zipped folder
  648.     if($tokenList[$tokenId]['type']=='directLink' && is_dir($tokenList[$tokenId]['filename'])){
  649.         // Generate zip and send it to output
  650.         efZipDownload(array(basename($tokenList[$tokenId]['filename']).'.zip' => $tokenList[$tokenId]['filename']),basename($tokenList[$tokenId]['filename']).'.zip',cfGGetVar('directLinkDownloadSpeedLimit'));
  651.         // Unset / modify token
  652.         efTokenDlFinished($tokenId);
  653.         exit();
  654.     }
  655.  
  656.     // Single file
  657.     if(!efForceDownload($tokenList[$tokenId]['filename'], $tokenList[$tokenId], $tokenId)) efDisplayError(403);
  658. }
  659.  
  660. /**
  661.  * @desc proceed to $completeFilename download (first checks access rights for new transfers)
  662.  *         Send HTTP headers and stream file
  663.  *
  664.  * @param string $completeFilename : path & filename of string
  665.  * @param array $token (optional - if not present, create new token) : download token
  666.  * @param string $tokenId (optional - if not present, create new token) : download token Id
  667.  * @return boolean : false if file not authorized or doesn't exist
  668.  */
  669. function efForceDownload($completeFilename, $token=false, $tokenId=false){
  670.     $range=0;
  671.     $completeFilename=cfCleanPathName($completeFilename);
  672.     $fileRightsOK=false;
  673.  
  674.     // Resource specific file source and rights function : bypass common file's existence and access rights
  675.     // and (may) replace given file name by real file name
  676.     if(substr($completeFilename,0,14)=='*resSpecific*/'){
  677.         if(cfRGetVar('extAccessFunction')) $extAccessFunction = create_function('$completeFilename', cfRGetVar('extAccessFunction'));
  678.         if(!($completeFilename=$extAccessFunction($completeFilename))) return false;
  679.         $fileRightsOK=true;
  680.     }
  681.  
  682.     // Generate token if needed
  683.     if(!$token){
  684.         // Token id sent by client
  685.         if(isset($_GET['data5']) && substr($_GET['data5'],0,7)=='dlToken'){
  686.             $tokenId = eregi_replace('[^0-9]','',substr($_GET['data5'],7));
  687.             if(!$fileRightsOK && !cfFileRights($completeFilename,'download')) return false; // if download not authorized, exit;
  688.             $tokenList=efTokensRead();
  689.             $tokenList[$tokenId]['type']='download';
  690.             $tokenList[$tokenId]['filename']=$completeFilename;
  691.             $tokenList[$tokenId]['creationTime']=time();
  692.             $tokenList[$tokenId]['userId']=$_SESSION['userId'];
  693.             $tokenList[$tokenId]['limitNb']="1";
  694.             $token=$tokenList[$tokenId];
  695.             efTokensWrite($tokenList);
  696.         }
  697.         // Else, simply download file, with no resume
  698.         else $token['type']='download';
  699.     }
  700.     // get HTTP header
  701.     $clientHeaders=getallheaders();
  702.     if(isset($clientHeaders['Range']) && strtolower(substr($clientHeaders['Range'],0,6)=='bytes=')){
  703.         $range=trim(substr($clientHeaders['Range'],6));
  704.     }
  705.     // process range request
  706.     if(isset($range) && strpos($range,'-')!==false){
  707.         $range=trim($range);
  708.         $fileSize=cfFileSize($completeFilename);
  709.  
  710.         // From
  711.         $from=substr($range,0,strpos($range,'-'));
  712.         if(!strlen($from)) $from=0;
  713.         if(!is_numeric($from) || $from>$fileSize) $rangeErr=true;
  714.  
  715.         // To
  716.         $rto=substr($range,strpos($range,'-')+1);
  717.         if(!strlen($rto)) {
  718.             $to = $fileSize-1;
  719.         }
  720.         else $to=$rto;
  721.         if($to+1>$fileSize || $to<$from) $rangeErr=true;
  722.         $content_size = 1 + $to - $from;
  723.  
  724.         // Incorrect range
  725.         if(isset($rangeErr)){
  726.             $range=false;
  727.             header('HTTP/1.1 416 Requested Range Not Satisfiable');
  728.             header("Content-Length: $content_size");
  729.         }
  730.         else{
  731.             header('HTTP/1.1 206 Partial Content');
  732.             header("Content-Range: bytes $from-$to/$fileSize");
  733.             header("Content-Length: $content_size");
  734.             $range=array('from'=>$from,'to'=>1+$to);
  735.         }
  736.     }
  737.     // no range request
  738.     else {
  739.         header('Content-Length: '.cfFileSize($completeFilename));
  740.     }
  741.  
  742.  
  743.     // Proceed to download
  744.     header("Accept-Ranges: bytes");
  745.     header("Pragma: public");
  746.     header("Cache-Control: must-revalidate");
  747.     header('Content-Type: '.efFileMimeType($completeFilename));
  748.     header('ETag: "'.md5($completeFilename).'"');
  749.     header('Content-Disposition: attachment; filename="'.cfUTF8Encode(basename($completeFilename),false,false).'"');
  750.     header('Last-Modified: '.gmdate("D, d M Y H:i:s",@filemtime($completeFilename)).' GMT');
  751.     header('Connection: close');
  752.  
  753.     // Log in viewed content history
  754.     cfLogContentAccess($completeFilename);
  755.  
  756.     // close session and stream file
  757.     if($token['type']=='download')    cfStreamFile($completeFilename,true,cfUGetVar('downloadSpeedLimit'),$range);
  758.     elseif($token['type']=='directLink') cfStreamFile($completeFilename,true,cfGGetVar('directLinkDownloadSpeedLimit'),$range);
  759.     // Clear download token
  760.     efTokenDlFinished($tokenId);
  761.     exit();
  762. }
  763.  
  764. /**
  765.  * @desc start remote download of $url file into $dir directory
  766.  * if $url valid && direct download authorized in $dir, send command and create corresponding transfers array
  767.  *
  768.  * @param unknown_type $dir
  769.  * @param unknown_type $url
  770.  * @return unknown
  771.  */
  772. function efRemoteDownload($dir, $url){
  773.     if(!cfFileRights($dir,'remoteDownload')) return false;
  774.     require_once(INCLUDE_DIR.'transferFunctions.php');
  775.     return tAddRemoteDownload($dir, $url);
  776. }
  777.  
  778.  
  779.  
  780. /*
  781. ***************************************************************************************************************************
  782. * Multiple downloads & playlist
  783. ***************************************************************************************************************************
  784. */
  785.  
  786. /**
  787.  * @desc : add a file to multiple download file list
  788.  *
  789.  * @param string $fileName : name (without path) of file to add (note : path is efCurrentDirectory)
  790.  */
  791. function efMultipleDownloadAdd($fileName){
  792.     cfAsyncHeader();
  793.     $completeFilename=cfJoinPathFile(cfRGetVar('efCurrentDirectory'),$fileName);
  794.  
  795.     // List items and into base directory: try to find file or directory
  796.     if(cfSharedMode('list') && cfRGetVar('efCurrentDirectory')=='*resourceBasePath*'){
  797.         foreach (cfSharedItems() as $cfn=>$type) if(basename($cfn)==$fileName){
  798.             $completeFilename=$cfn;
  799.             break;
  800.         }
  801.     }
  802.  
  803.     // If file doesn't exists or user doesn't have access rights, do nothing
  804.     if((is_file($completeFilename) && cfFileRights($completeFilename,'download')) || (is_dir($completeFilename) && cfFileRights($completeFilename,'read'))) {
  805.         if(!cfRGetVar('mDownloadList',$fileName)){// if a file with same name (but possibly different dir...) is present, abort
  806.             // Update total file number and size
  807.             if(cfHGetVar('mDownloadPrecomputeSize')){
  808.                 list($nbFiles,$totalSize)=cfRGetVar('mDownloadTotals');
  809.                 if(is_file($completeFilename)){
  810.                     $nbFiles++;
  811.                     $totalSize+=cfFileSize($completeFilename);
  812.                     // Store total files nb and size in mDownloadListTotals
  813.                     cfRSetVar('mDownloadListTotals',$fileName, array(1,cfFileSize($completeFilename)));
  814.                 }
  815.                 else {
  816.                     list($nbFilesD,$totalSizeD)=efDirGetFilesSize($completeFilename);
  817.  
  818.                     // Store total files nb and size in mDownloadListTotals
  819.                     cfRSetVar('mDownloadListTotals', $fileName, array($nbFilesD,$totalSizeD));
  820.                     $nbFiles+=$nbFilesD;$totalSize+=$totalSizeD;
  821.                 }
  822.                 cfRSetVar('mDownloadTotals',array($nbFiles,$totalSize));
  823.             }
  824.             // Store added file/dir in mDownloadList
  825.             cfRSetVar('mDownloadList',$fileName, $completeFilename);
  826.  
  827.             // Update buttons
  828.             echo efMultipleDownloadUpdateBt();
  829.  
  830.             // Update webpage's list
  831.             echo cfAsyncXMLInnerHTMLbyId(outMultipleDownloadListInnerHTML(),'mDlList');
  832.         }
  833.     }
  834.     echo cfAsyncXMLJSaction('mProcessing(false)');// Update reloading icon
  835.     die(cfAsyncFooter());
  836. }
  837.  
  838. /**
  839.  * @desc : add all current directory files (but no folder) to multiple download file list
  840.  *
  841.  */
  842. function efMultipleDownloadAddAll(){
  843.     $fileAdded=false;
  844.     cfAsyncHeader();
  845.     if(!isset($_ENV['weezoResEfFiles'])) efDirUpdate();
  846.  
  847.     // Update total file number and size
  848.     if(cfHGetVar('mDownloadPrecomputeSize')){
  849.         list($nbFiles,$totalSize)=cfRGetVar('mDownloadTotals');
  850.         $totals=true;
  851.         $nbFilesD=0;
  852.         $totalSizeD=0;
  853.     }
  854.     else $totals=false;
  855.  
  856.     $mDownloadList=cfRGetVar('mDownloadList');
  857.     if($totals) $mDownloadListTotals=cfRGetVar('mDownloadListTotals');
  858.  
  859.  
  860.     // For each file in current directory
  861.     foreach ($_ENV['weezoResEfFiles'] as $value) if(isset($value['type']) && $value['type']=='file') {
  862.         $completeFilename=$value['completeFileName'];
  863.  
  864.         // If file download authorized
  865.         if(cfFileRights($completeFilename,'download',false)){
  866.  
  867.             // Add to mDownload list
  868.             if(!isset($mDownloadList[$value['name']])){// if a file with same name (but possibly different dir...) is present, abort
  869.                 $mDownloadList[$value['name']]=$completeFilename;
  870.                 if($totals){
  871.                     $nbFilesD++;
  872.                     $totalSizeD+=cfFileSize($completeFilename);
  873.                     // Store files nb and size in mDownloadListTotals
  874.                     $mDownloadListTotals[$value['name']]=array(1,cfFileSize($completeFilename));
  875.                 }
  876.                 $fileAdded=true;
  877.             }
  878.         }
  879.         cfPingUpdate(100); // Ping app one
  880.     }
  881.  
  882.     // Mobile view
  883.     if(cfIsMobile() && $fileAdded){
  884.         cfRSetVar('mDownloadList',$mDownloadList);
  885.         echo cfAsyncXMLInnerHTMLbyId(mefMultipleDownloadsInnerHTML(),'mdlF');
  886.     }
  887.     // Normal view, update only if new files
  888.     elseif($fileAdded){
  889.         cfRSetVar('mDownloadList',$mDownloadList);
  890.         if($totals) cfRSetVar('mDownloadListTotals',$mDownloadListTotals);
  891.  
  892.         if(cfHGetVar('mDownloadPrecomputeSize')){
  893.             // Update totals
  894.             cfRSetVar('mDownloadTotals',array($nbFiles+$nbFilesD,$totalSize+$totalSizeD));
  895.         }
  896.         // Update mdl buttons state
  897.         echo efMultipleDownloadUpdateBt();
  898.         // Update webpage's list
  899.         echo cfAsyncXMLInnerHTMLbyId(outMultipleDownloadListInnerHTML(),'mDlList');
  900.     }
  901.     if(!cfIsMobile()) echo cfAsyncXMLJSaction('mProcessing(false)');// Update reloading icon
  902.  
  903.     die(cfAsyncFooter());
  904. }
  905.  
  906. /**
  907.  * @desc : remove a file from multiple download file list
  908.  *
  909.  * @param string $fileName : name (without path) of file to remove (note : path is efCurrentDirectory)
  910.  */
  911. function efMultipleDownloadSupp($fileName){
  912.     header('Content-Type:text/xml');
  913.     echo '<?xml version="1.0" encoding="utf-8"?><response>'."\n";
  914.     if(is_array(cfRGetVar('mDownloadList')) && cfRGetVar('mDownloadList',$fileName)){// if passed file is in list
  915.  
  916.         // Remove file/folder from list
  917.         $mdl=cfRGetVar('mDownloadList');
  918.         $completeFilename=$mdl[$fileName];
  919.         unset($mdl[$fileName]);
  920.         cfRSetVar('mDownloadList',$mdl);
  921.  
  922.         // Update total file number and size
  923.         if(cfHGetVar('mDownloadPrecomputeSize')){
  924.             // Remove nb files and size info from list
  925.             $mdl=cfRGetVar('mDownloadListTotals');
  926.             list($nbFilesD,$totalSizeD)=$mdl[$fileName];
  927.             unset($mdl[$fileName]);
  928.             cfRSetVar('mDownloadListTotals',$mdl);
  929.             unset($mdl);
  930.  
  931.             // Update totals
  932.             list($nbFiles,$totalSize)=cfRGetVar('mDownloadTotals');
  933.             cfRSetVar('mDownloadTotals',array($nbFiles-$nbFilesD,$totalSize-$totalSizeD));
  934.         }
  935.  
  936.         // Update mdl buttons state
  937.         echo efMultipleDownloadUpdateBt();
  938.         // Update webpage's list
  939.         echo cfAsyncXMLInnerHTMLbyId(outMultipleDownloadListInnerHTML(),'mDlList');
  940.     }
  941.     echo cfAsyncXMLJSaction('mProcessing(false)');// Update reloading icon
  942.     echo cfAsyncFooter();
  943.     exit;
  944. }
  945.  
  946. /**
  947.  * @desc : clear multiple download file list
  948.  *
  949.  */
  950. function efMultipleDownloadClear(){
  951.     cfRUnsetVar('mDownloadList');
  952.     cfRSetVarArray('mDownloadList');
  953.     cfRUnsetVar('mDownloadListTotals');
  954.     cfRSetVarArray('mDownloadListTotals');
  955.     cfAsyncHeader();
  956.  
  957.     // Update totals
  958.     cfRSetVar('mDownloadTotals',array(0,0));
  959.  
  960.     // Update mdl buttons state
  961.     echo efMultipleDownloadUpdateBt();
  962.  
  963.     // Update webpage's list
  964.     echo cfAsyncXMLInnerHTMLbyId(outMultipleDownloadListInnerHTML(),'mDlList');
  965.     echo cfAsyncXMLJSaction('mProcessing(false)');// Update reloading icon
  966.     echo cfAsyncFooter();
  967.     exit;
  968. }
  969.  
  970. /**
  971.  * @desc return async HTML code for updating multiple download buttons
  972.  *
  973.  * @return string : HTML code
  974.  */
  975. function efMultipleDownloadUpdateBt(){
  976.     if(cfHGetVar('mDownloadPrecomputeSize')){
  977.         list($nbFiles,$totalSize)=cfRGetVar('mDownloadTotals');
  978.         $output=cfAsyncXMLInnerHTMLbyId('('.cfCaption('explorerFiles',$nbFiles).' / '.efFileSizeFormat($totalSize).')','mDlTotals');
  979.     }
  980.     if(cfRGetVar('mDownloadList')) $output.=cfAsyncXMLJSaction('mToggleButtons(true)'); else $output.=cfAsyncXMLJSaction('mToggleButtons(false)');
  981.     return $output;
  982. }
  983.  
  984. /**
  985.  * @recursively add dir and files to zip (used by efMultipleDownloadDownload)
  986.  *
  987.  * @param zipfile $zip
  988.  * @param srting $completeFilename : complete file name of directory to add
  989.  * @param string $baseName : path name beetween zip root and current dir
  990.  */
  991. function mdlAddDir(&$zip, $completeFilename, $baseName){
  992.     global $protectSensitiveFiles;
  993.     global $protectedFileExtension;
  994.     global $protectedDirectories;
  995.  
  996.     $isDlToken=cfCmpLeft($_SERVER['REQUEST_URI'],'/downloads/dlToken');
  997.  
  998.     if(!($handle = opendir($completeFilename))) return;
  999.     $zip->add_dir($completeFilename,$baseName);
  1000.  
  1001.     while (($file = @readdir($handle))!==false) {
  1002.         //set_time_limit(10);
  1003.         if($file!='.' && $file!='..'){
  1004.             $f=$completeFilename.'/'.$file;
  1005.             // Check individual file access rights
  1006.             // (disabled if not linked to a resource or that resource doesn't have a path property)
  1007.             if(is_file($f) && ($isDlToken || !cfRGetVar('path') || cfFileRights($f,'download'))){
  1008.                 if(!$protectSensitiveFiles || in_array(cfFileExtension($file),$protectedFileExtension)===false) $zip->add_File($f, $baseName.'/'.$file);
  1009.             }
  1010.             elseif (is_dir($f) && !cfIsGeneralProtected($f,$protectedDirectories)) mdlAddDir($zip, $f, $baseName.'/'.$file);
  1011.         }
  1012.     }
  1013. }
  1014.  
  1015. /**
  1016.  * @desc launch multiple download containing cfRGetVar('mDownloadList') file list
  1017.  *         No buffering, directly send zip to output
  1018.  *
  1019.  */
  1020. function efMultipleDownloadDownload(){
  1021.     global $protectSensitiveFiles;
  1022.     if(!is_array(cfRGetVar('mDownloadList'))) exit; // If list is empty (shouldn't happend), exit
  1023.  
  1024.     // Create resource specific file convertion / rights function if needed
  1025.     if(cfRGetVar('extAccessFunction')) $extAccessFunction = create_function('$completeFilename', cfRGetVar('extAccessFunction'));
  1026.  
  1027.     $zips=array();
  1028.     foreach (cfRGetVar('mDownloadList') as $fileName=>$completeFilename) {
  1029.         $fileRightsOK=false;
  1030.         if(substr($completeFilename,0,14)=='*resSpecific*/') {
  1031.             if(($completeFilename=$extAccessFunction($completeFilename))!==false) {
  1032.                 $fileName=basename($completeFilename);
  1033.                 $fileRightsOK=true;
  1034.             }
  1035.         }
  1036.         if(is_file($completeFilename) && ($fileRightsOK || cfFileRights($completeFilename,'download'))){
  1037.             $outputFileName=$fileName;
  1038.             $zips[$fileName]=cfCleanPathName($completeFilename);
  1039.         }
  1040.         elseif (is_dir($completeFilename) && ($fileRightsOK || cfFileRights($completeFilename,'read'))){
  1041.             $outputFileName=$fileName;
  1042.             $zips[$fileName]=cfCleanPathName($completeFilename);
  1043.         }
  1044.     }
  1045.     // If list is empty (shouldn't happend), exit
  1046.     if(!count($zips)) exit;
  1047.  
  1048.     // Name output zip file
  1049.     if(count($zips)==1) $outputFileName.='.zip'; else $outputFileName=cfcaption('multipleDownloadFileName');
  1050.  
  1051.     // Generate and send zip to output
  1052.     efZipDownload($zips, $outputFileName, cfUGetVar('downloadSpeedLimit'));
  1053.     exit;
  1054. }
  1055.  
  1056. /**
  1057.  * @desc Generate .torrent file from files contained in cfRGetVar('mDownloadList'), and send .torrent file to output
  1058.  *
  1059.  */
  1060. function efMultipleDownloadCreateTorrent(){
  1061.     // If list is empty (shouldn't happend), exit
  1062.     if(!is_array(cfRGetVar('mDownloadList'))) exit;
  1063.     require_once(INCLUDE_DIR.'transferFunctions.php');
  1064.  
  1065.     // Create transfer and .torrent file
  1066.     $tr=tAddBittorrentDownload(array_values(cfRGetVar('mDownloadList')),$metainfo);
  1067.  
  1068.     // Failure
  1069.     if(!$metainfo) outDisplayErrorPage('Bittorrent file generation error<br/>'.outButton(cfCaption('genBack'),'javascript:history.back()',outIcon('back')));
  1070.  
  1071.     // .torrent file header
  1072.     header('Content-Type: application/x-bittorrent');
  1073.     header('Content-Disposition: attachment; filename="'.cfUTF8Encode($tr->destinationFile).'"');
  1074.     header('Content-Length: '.strlen($metainfo));
  1075.     echo $metainfo;
  1076.     exit;
  1077. }
  1078.  
  1079. /**
  1080.  * @desc Create torrent in transfers list, and return .torrent content
  1081.  *
  1082.  * @param array $files
  1083.  * @param string $tokenId: id of directLink or publishDownload
  1084.  * @param array $options: see tAddBittorrentDownload for details
  1085.  * @return array(transfer id, torrent file binary content)
  1086.  */
  1087. function efTorrentCreate($files, $tokenId=false, $options=array()){
  1088.     require_once(INCLUDE_DIR.'transferFunctions.php');
  1089.  
  1090.     // Create transfer and .torrent file
  1091.     $tr=tAddBittorrentDownload(array_values($files),$metainfo,$tokenId,$options);
  1092.  
  1093.     if(!$tr) return array(false,false);
  1094.     return array($tr->id,$metainfo);
  1095. }
  1096.  
  1097. /**
  1098.  * @desc generate and send a zip file to browser
  1099.  *
  1100.  * @param array $files : files and folders put in zip (filename1 => completeFilename1,
  1101.  * @param string $outputFileName : generated zip file name
  1102.  * @param int $speedLimit : download speed limit
  1103.  */
  1104. function efZipDownload($files, $outputFileName, $speedLimit=false, $isTransfer=true){
  1105.     require(INCLUDE_DIR.'zip.php');
  1106.     require(INCLUDE_DIR.'transferFunctions.php');
  1107.  
  1108.     // Store protected directories and files before closing session
  1109.     $protectSensitiveFiles=cfGGetVar('protectSensitiveFiles');
  1110.     $protectedDirectories=cfGGetVar('protectedDirs');
  1111.  
  1112.     // Headers
  1113.     wSession_write_close();
  1114.     set_time_limit(0);
  1115.     header("Pragma: public");
  1116.     header('Content-Description: file Transfert');
  1117.     Header("Content-type: application/x-zip");
  1118.     Header('Content-disposition: attachment; filename="'.cfUTF8Encode($outputFileName).'"');
  1119.     header("Content-Transfer-Encoding: binary");
  1120.     header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
  1121.     header("Expires: 0");
  1122.  
  1123.  
  1124.     // Create zip file
  1125.     $zip = new zipfile2();
  1126.     $zip->setSpeedLimit($speedLimit);
  1127.     if($isTransfer) $zip->t=tAddMultipleDownload($outputFileName); // Monitor multiple download as transfer
  1128.     if(cfHGetVar('mDownloadPrecomputeSize')) list($nbFiles,$zip->uncompressedSize)=cfRGetVar('mDownloadTotals'); else $zip->uncompressedSize=0;
  1129.  
  1130.     // Add files and dirs to zip
  1131.     foreach ($files as $fileName=>$completeFilename){
  1132.         if(is_file($completeFilename)) $zip->add_File($completeFilename, $fileName);
  1133.         elseif (is_dir($completeFilename)) mdlAddDir($zip, $completeFilename, basename($completeFilename));
  1134.     }
  1135.     // Send zip central directory
  1136.     $zip->file();
  1137.  
  1138.     if($isTransfer) $zip->t->updateStatus(4,true); // Set transfer as finished
  1139. }
  1140.  
  1141. /**
  1142.  * @desc : generate multiple downloads list from playlist
  1143.  *
  1144.  */
  1145. function efConvertPlayListToMDList(){
  1146.     //if(!cfRGetVar('multipleDownloadAllowed')) return;
  1147.     $mdl=array();
  1148.     foreach (cfRGetVar('playlist') as $value) $mdl[basename($value['completeFileName'])]=$value['completeFileName'];
  1149.     cfRSetVar('mDownloadList',$mdl);
  1150. }
  1151.  
  1152. /**
  1153.  * @desc Generate JS Array to send to plRefresh JS function for refreshing playlist display
  1154.  * @desc string : JS Array : Array(filename1,label1, filename2,label2,...)
  1155.  *
  1156.  */
  1157. function efPlayListContentArray(){
  1158.     $arrayMainPlaylist='Array(';
  1159.     $itemsFound=false;
  1160.     if(!is_array(cfRGetVar('playlist')) || count(cfRGetVar('playlist'))==0) {}
  1161.     // Playlist files
  1162.     else foreach (cfRGetVar('playlist') as $key=>$song) {
  1163.         if($itemsFound) $arrayMainPlaylist.=','; else $itemsFound=true;
  1164.         // File name
  1165.         if(substr($song['completeFileName'],0,14)=='*resSpecific*/') $arrayMainPlaylist.='"'.cfProtectFilename($song['completeFileName']).'",';
  1166.         else $arrayMainPlaylist.='"'.cfProtectFilename(cfResourceRelativePath($song['completeFileName'])).'",';
  1167.         // File label
  1168.         $arrayMainPlaylist.='"'.str_replace('"','\\"',stripslashes(cfUTF8Encode($song['label']))).'"';
  1169.     }
  1170.     return $arrayMainPlaylist.')';
  1171. }
  1172.  
  1173. /**
  1174.  * @desc Return true if supported playlist format
  1175.  *
  1176.  * @param string $n: filenam
  1177.  * @return bool
  1178.  */
  1179. function efIsPlaylist($n){
  1180.     $e=cfFileExtension($n);
  1181.     if($e=='m3u') return true;
  1182. }
  1183.  
  1184.  
  1185.  
  1186.  
  1187. /*
  1188. ***************************************************************************************************************************
  1189. * Misc functions
  1190. ***************************************************************************************************************************
  1191. */
  1192.  
  1193.  
  1194. /**
  1195.  * @desc  Return path where images and video thumbnails should be place, create directory if needed
  1196.  *
  1197.  * @return string
  1198.  */
  1199. function efThumbnailsPath(){
  1200.     if(cfSharedMode('list')){
  1201.         $thumbnailsPath=cfJoinPathFile(cfRGetVar('resourceDataDir').'/list/',substr(cfResourceRelativePath(cfRGetVar('efCurrentDirectory')),18));
  1202.         if(substr($thumbnailsPath,-1)=='/') $thumbnailsPath=cfStrShorten($thumbnailsPath,1);
  1203.     }
  1204.     else{
  1205.         if(cfRGetVar('path')!='computerRoot') $thumbnailsPath=cfRGetVar('resourceDataDir').substr(cfRGetVar('efCurrentDirectory'), strlen(cfCleanPathName(cfRGetVar('path'))));
  1206.         else $thumbnailsPath=cfRGetVar('resourceDataDir').'/'.str_replace(':/','/',cfRGetVar('efCurrentDirectory'));
  1207.     }
  1208.     // Create thumbnails dir if non-existant
  1209.     if(!is_dir($thumbnailsPath)) cfMkdir($thumbnailsPath,null,true,null);
  1210.     return $thumbnailsPath;
  1211. }
  1212.  
  1213. /**
  1214.  * @desc Return thumbnails max width
  1215.  *
  1216.  * @return integer
  1217.  */
  1218. function efThumbnailsMaxWidth(){
  1219.     $s=cfRGetVar('thumbnailsSize');
  1220.     $sf=cfRGetVar('thumbnailsSizeFactor');
  1221.     if($sf==2) return (cfRGetVar('cropThumbnails'))?floor($s*2/3):$s;
  1222.     return floor(min(4,(pow($sf,2)+1))*$s/4);
  1223. }
  1224.  
  1225. /**
  1226.  * @desc Generate video thumbnail
  1227.  *
  1228.  * @param string $source: source complete filename
  1229.  * @param string $destination: jpg destination complete filename, falses to send to output
  1230.  * @param int $w: dest max width
  1231.  * @param int $h: dest max height
  1232.  * @param int $q: dest JPG quality (1-100)
  1233.  * @param int $videoThumbnailOffset: offset from start (seconds)
  1234.  */
  1235. function efMakeVideoThumbnail($source,$destination,$w=0,$h=0,$q=0,$videoThumbnailOffset=0){
  1236.     if(!$w) $w=cfRGetVar('thumbnailsSize');
  1237.     if(!$h) $h=cfRGetVar('thumbnailsSize');
  1238.     if(!$q) $q=DEFAULT_JPG_QUALITY;
  1239.     $w=2*(floor($w/2));
  1240.     $h=2*(floor($h/2));
  1241.  
  1242.     if($videoThumbnailOffset==0) $videoThumbnailOffset=(int)cfRGetVar('videoThumbnailOffset');
  1243.  
  1244.     // Generate image from video
  1245.     $cl='-i "'.$source.'" -vframes 1 -ss '.(int)$videoThumbnailOffset.' -an "'.cfAppDataDir().'/temp/temp%0d.jpg"';
  1246.     cfFfmpegExec($cl);
  1247.  
  1248.     // If failure, try to generate image from frame 0
  1249.     if(!file_exists(cfAppDataDir().'/temp/temp1.jpg')){
  1250.         $cl='-i "'.$source.'" -vframes 1 -ss 0 -an "'.cfAppDataDir().'/temp/temp%0d.jpg"';
  1251.         cfFfmpegExec($cl);
  1252.         if(!file_exists(cfAppDataDir().'/temp/temp1.jpg')) return false;
  1253.     }
  1254.  
  1255.     // Resize thumbnail from image
  1256.     cfCreateResizedJPG(cfAppDataDir().'/temp/temp1.jpg',0,0,$destination,$w,$h,4,$q);
  1257.     @unlink(cfAppDataDir().'/temp/temp1.jpg');
  1258.     return true;
  1259. }
  1260.  
  1261. /**
  1262.  * @desc Display a progress bar and generate video thumbnails
  1263.  *
  1264.  * @param array $thumbnails
  1265.  */
  1266. function efMakeVideoThumbnails($thumbnails){
  1267.     // IE doesn't support real-time async processing: if more than 5 thumbnails, sync reload page
  1268.     if(cfIsAsync() && count($thumbnails)>2 && !cfBGetVar('asyncHTTPStreaming')) {
  1269.         echo cfAsyncXMLJSaction('wl.goURL()');
  1270.         die(cfAsyncFooter());
  1271.     }
  1272.  
  1273.     // Display monitoring stuff
  1274.     cfRTScript('var tMN=D.createElement("DIV");tMN.id="tnMonitoringDiv";tMN.style.display="'.((cfIsAsync())?'none':'').'";tMN.innerHTML=\'<div class="mask" id="tnMonitoringMask"> </div><div style="position:absolute;top:50%;left:50%;z-index:999999"><div class="popup" style="width:24em;left:-12em;top:-4em">'.outFrameHeaderTable('popupHeader',outImage(outIcon('loading'),false,false,'vertical-align:middle;margin-right:0.5em').cfCaption('genThumbnails'),outImage(outIcon('fi/icovid'),false,false,'vertical-align:middle')).'<br><center>'.outProgressBar(0,'80%','0/'.count($thumbnails),'tnProg').'</center><br></div></div>\';D.body.appendChild(tMN);');
  1275.  
  1276.     set_time_limit(0); $nb=0;
  1277.     foreach ($thumbnails as $completeFilename=>$destination){
  1278.         // Update progress bar
  1279.         cfRTScript('tnUpdt("'.$nb.' / '.count($thumbnails).'",'.floor(100*$nb/count($thumbnails)).')');
  1280.         // Generate thumbnail
  1281.         efMakeVideoThumbnail($completeFilename,$destination,cfRGetVar('thumbnailsSize'),cfRGetVar('thumbnailsSize'));
  1282.         $nb++;
  1283.     }
  1284.     cfRTScript('removeNode(dgi("tnMonitoringDiv"))');
  1285.     set_time_limit(ini_get('max_execution_time'));
  1286. }
  1287.  
  1288. /**
  1289.  * @desc Display a progress bar and generate photo thumbnails
  1290.  *
  1291.  * @param array $path: source directory
  1292.  * @param array $thumbnailsPath: destination directory
  1293.  */
  1294. function efMakePhotoThumbnails($thumbnails){
  1295.     // IE doesn't support real-time async processing: if more than 5 thumbnails, sync reload page
  1296.     if(cfIsAsync() && count($thumbnails)>5 && !cfBGetVar('asyncHTTPStreaming')) {
  1297.         echo cfAsyncXMLJSaction('wl.goURL()');
  1298.         die(cfAsyncFooter());
  1299.     }
  1300.  
  1301.     // Base thumbnails should be better encoded as they are bound to be reecoded one more time => set min quality to 90%
  1302.     $thumbnailJPGQuality=max(90,cfHGetVar('thumbnailJPGQuality',DEFAULT_JPG_QUALITY));
  1303.  
  1304.     // Called by cfStreamProc on data reception
  1305.     function efMakePhotoThumbnailsCB($buff){
  1306.         static $nbPhotoThumbnails=0;
  1307.         static $nbPhotoThumbnailsProcessed=0;
  1308.         static $remBuff='';
  1309.         static $lastUpdate;
  1310.  
  1311.         // Init total number of thumbnails to be processed
  1312.         if(is_integer($buff)) {
  1313.             $nbPhotoThumbnails=$buff;
  1314.             return;
  1315.         }
  1316.  
  1317.         $buff=$remBuff.$buff;
  1318.         $remBuff=substr($buff,strrpos($buff,'OK')+2);
  1319.         // Count newly created thumbnails
  1320.         str_replace('OK','',$buff,$cnt);
  1321.         // If any
  1322.         if($cnt){
  1323.             $nbPhotoThumbnailsProcessed+=$cnt;
  1324.             // Update progress bar
  1325.             if(microtime(true)>$lastUpdate+0.5){
  1326.                 cfRTScript('tnUpdt("'.$nbPhotoThumbnailsProcessed.' / '.$nbPhotoThumbnails.'",'.floor(100*$nbPhotoThumbnailsProcessed/$nbPhotoThumbnails).');');
  1327.                 $lastUpdate=microtime(true);
  1328.             }
  1329.         }
  1330.     }
  1331.  
  1332.     // Display synchronous monitoring stuff
  1333.     cfRTScript('var tMN=D.createElement("DIV");tMN.id="tnMonitoringDiv";tMN.style.display="'.((cfIsAsync())?'none':'').'";tMN.innerHTML=\'<div class="mask" id="tnMonitoringMask"> </div><div style="position:absolute;top:50%;left:50%;z-index:999999"><div class="popup" style="width:24em;left:-12em;top:-4em">'.outFrameHeaderTable('popupHeader',outImage(outIcon('loading'),false,false,'vertical-align:middle;margin-right:0.5em').cfCaption('genThumbnails'),outImage(outIcon('fi/icoImage'),false,false,'vertical-align:middle')).'<br><center>'.outProgressBar(0,'80%','0/'.count($thumbnails),'tnProg').'</center><br></div></div>\';D.body.appendChild(tMN)');
  1334.  
  1335.     set_time_limit(0); $nb=0;
  1336.     $tnSize=cfRGetVar('thumbnailsSize');
  1337.  
  1338.     // Disabled use of createJPG: PHP-generate
  1339.     if(cfGGetVar('disableCreateJPG') || (cfSharedMode('list') && cfRGetVar('efCurrentDirectory')=='*resourceBasePath*')){
  1340.         foreach ($thumbnails as $completeFilename=>$destination){
  1341.             // Update progress bar
  1342.             cfRTScript('tnUpdt("'.$nb.' / '.count($thumbnails).'",'.floor(100*$nb/count($thumbnails)).');');
  1343.             // Generate thumbnail (no more cropping on TN as it's done when actually displaying TNs)
  1344.             cfCreateResizedJPG($completeFilename,0,0,$destination,$tnSize,$tnSize,DEFAULT_RESIZE_METHOD,$thumbnailJPGQuality,0,0/*cfRGetVar('cropThumbnails')*/);
  1345.             $nb++;
  1346.         }
  1347.     }
  1348.     // Use CreateJPG to generate thumbnails
  1349.     else{
  1350.         // Init efMakePhotoThumbnailsCB function
  1351.         efMakePhotoThumbnailsCB(count($thumbnails));
  1352.         $cl='"'.cfRGetVar('efCurrentDirectory').'" "'.dirname(reset($thumbnails)).'" '.$tnSize.' '.$tnSize.' images';
  1353.         /*if(cfRGetVar('cropThumbnails')) $cl.=' square 100'; else */$cl.=' no 100'; // (no more cropping on TN as it's done when actually displaying TNs)
  1354.         $cl.=' '.$thumbnailJPGQuality;
  1355.  
  1356.         // Launch createJPG and monitor stdout with efMakePhotoThumbnailsCB
  1357.         $output=array('stdout'=>'efMakePhotoThumbnailsCB');
  1358.         cfStreamProc('"'.cfAppBinDir().'/createJPG.exe" '.$cl,$output,array('bufferSize'=>10,'haltOnSeq'=>chr(12)));
  1359.     }
  1360.     cfRTScript('removeNode(dgi("tnMonitoringDiv"))');
  1361.     set_time_limit(ini_get('max_execution_time'));
  1362. }
  1363.  
  1364. /**
  1365.  * @desc Return best-suited image as a cover for an audio file, from all images located in directory
  1366.  *
  1367.  * @param string $completeFilename: audio complete filename
  1368.  * @param integer $score: matching criterias score
  1369.  * @return string: cover image complete filename
  1370.  */
  1371. function efGetCoverFromFolder($completeFilename, &$score=0){
  1372.     if($completeFilename=='*resourceBasePath*') $folder='';
  1373.     elseif(is_dir($completeFilename)){
  1374.         $filename=false;
  1375.         $folder=$completeFilename;
  1376.     }
  1377.     else{
  1378.         $folder=dirname($completeFilename);
  1379.         $filename=basename($completeFilename);
  1380.     }
  1381.  
  1382.     $images=glob($folder.'/{*.jpg,*.JPG,*.gif,*.GIF,*.png,*.png}',GLOB_BRACE);
  1383.     // Default image
  1384.     $score=-1;
  1385.  
  1386.     if(!count($images)) return cfAppDocRoot().'/gfx/cover.png';
  1387.     $score=0;
  1388.     if(count($images)==1) return $images[0];
  1389.  
  1390.     // Browse images to find the best-matching
  1391.     $max=0;
  1392.     $bestImage='';
  1393.     foreach ($images as $imageCompleteFilename){
  1394.         $imageFilename=basename($imageCompleteFilename);
  1395.         $imageFilenameLC=strtolower($imageFilename);
  1396.         $score=0;
  1397.         if(strpos($imageFilenameLC,'cover')!==false) $score+=5;
  1398.         if(strpos($imageFilenameLC,'front')!==false) $score+=3;
  1399.         if(strpos($imageFilenameLC,'back')!==false) $score+=2;
  1400.         if(strpos($imageFilenameLC,'.jpg')) $score+=1;
  1401.         $imageFilename=str_ireplace('cover','',str_ireplace('front','',cfFileWithoutExtension($imageFilename)));
  1402.         similar_text(cfFileWithoutExtension($filename),cfFileWithoutExtension($imageFilename),$perc);
  1403.         if($perc>50) $score+=$perc/10;
  1404.         if($score>=$max) {
  1405.             $max=$score;
  1406.             $bestImage=$imageCompleteFilename;
  1407.         }
  1408.     }
  1409.     $score=$max;
  1410.     //cfDbg($completeFilename.'=>'.$bestImage.' ('.$score,1);
  1411.     return $bestImage;
  1412. }
  1413.  
  1414. /**
  1415.  * @desc search COMMENTS_FILE (located in $thumbnailsPath) for a line starting with "$imageName=" and return the right part of the line
  1416.  * @return mixed : false if error or $imageName not found, comments if image found
  1417.  * @param string $thumbnailsPath
  1418.  * @param string $imageName
  1419. */
  1420. function efReadComments($completeFilename){
  1421.     $completeFilename=strtolower($completeFilename);
  1422.     $imageName=basename($completeFilename);
  1423.     $subPath=substr(cfDirName($completeFilename),strlen(cfRGetVar('path'))); // path between album base directory and current image's directory
  1424.     $commentsFilePath=cfJoinPathFile(cfAppResourceDir(),$subPath); // Path in which comments text file is stored
  1425.     if(!file_exists($commentsFilePath)) return false; // If this path doesn't exist, return false
  1426.     $commentsFileName=cfJoinPathFile($commentsFilePath, COMMENTS_FILE); // Comments text file complete file name
  1427.     if(!file_exists($commentsFileName) || !($handle= fopen($commentsFileName,"r"))) return false; // If comments file doesn't exist or cannot be opened, return false
  1428.     if(strlen($imageName)<3) return false;
  1429.     if(substr($imageName,0,1)=='/') $imageName=substr($imageName,1);
  1430.  
  1431.     while(!feof($handle)){
  1432.         $textLine = trim(fgets($handle));
  1433.         if(strtolower(substr($textLine,1,strlen($imageName)))==$imageName && substr($textLine,strlen($imageName)+1,1)=='"' && (substr(ltrim(substr($textLine,strlen($imageName)+2)),0,1)=="=")) {fclose($handle); return substr(ltrim(substr($textLine,strlen($imageName)+2)),1);}
  1434.     }
  1435.     fclose($handle);
  1436.     return false;
  1437. }
  1438.  
  1439. /**
  1440.  * @desc : write user comments on file $completeFilename, in comments text file
  1441.  * Comments file is named COMMENTS_FILE and is located in $thumbnailsPath.
  1442.  * Written string is "$imageName=$comments"
  1443.  *
  1444.  * @param string $completeFilename : path and file name of commented file
  1445.  * @param string $comments : comments
  1446.  * @param bool $append : If append is true, append this line at the end of file, else replace existing line
  1447.  * @return boolean : result of operation
  1448.  */
  1449. function efWriteComments($completeFilename, $comments, $append){
  1450.     $fileName=basename($completeFilename);
  1451.     $subPath=substr(cfDirName($completeFilename),strlen(cfRGetVar('path'))); // path between album base directory and current image's directory
  1452.     $commentsFilePath=cfJoinPathFile(cfAppResourceDir(),$subPath); // Path in which comments text file is stored
  1453.     if(!file_exists($commentsFilePath)) if(!mkdir($commentsFilePath)) return false; // If this path doesn't exist, try to create it
  1454.     $commentsFileName=cfJoinPathFile($commentsFilePath, COMMENTS_FILE); // Comments text file complete file name
  1455.  
  1456.     // If comments file doesn't exist : create it and write line
  1457.     if(!file_exists($commentsFileName)){
  1458.         if(!($handle= fopen($commentsFileName,"w"))) return false;
  1459.         fwrite($handle, '"'.$fileName.'"='.$comments);
  1460.         fclose($handle);
  1461.         return true;
  1462.     }
  1463.  
  1464.  
  1465.     // find image's entry in file
  1466.     if(!($handle= fopen($commentsFileName,"r"))) return false;
  1467.     $lines=array();
  1468.     $lines[0]='"'.$fileName.'"='.$comments."\n";
  1469.     $nbLines=1; $found=false;
  1470.     while(!feof($handle)){
  1471.         $textLine = trim(fgets($handle));
  1472.         if(!$found && substr($textLine,1,strlen($fileName))==$fileName && substr($textLine,strlen($fileName)+1,1)=='"' && (substr(ltrim(substr($textLine,strlen($fileName)+2)),0,1)=="=")) $found=true;
  1473.         elseif(strlen($textLine)>8) $lines[$nbLines++]=$textLine."\n";
  1474.     }
  1475.     fclose($handle);
  1476.  
  1477.     // erase and rewrite file
  1478.     if(!($handle= fopen($commentsFileName,"w"))) {unset($lines); return false;}
  1479.     for($i=0;$i<$nbLines;$i++) fwrite($handle, $lines[$i]);
  1480.     fclose($handle);
  1481.     unset($lines);
  1482.     return true;
  1483. }
  1484.  
  1485. /**
  1486.  * @desc unlink $passedDir/$passedFile (first checks access rights)
  1487.  * if $passedFile is a non-empty directory, recursively deletes sub files and folders
  1488.  *
  1489.  * @param string $completeFilename : file or dir name
  1490.  * @return boolean : result of unlink
  1491.  */
  1492. function efUnlink($completeFilename){
  1493.     // if no general modify and write authorizations, return false
  1494.     if(cfGGetVar('generalModifyProtection') || !(cfRGetVar('modifyAllowed') || cfGGetVar('generalWriteProtection') || !(cfRGetVar('writeAllowed')))) return false;
  1495.     if(!file_exists($completeFilename) || !cfFileRights($completeFilename,'modify')) return false;
  1496.     // Destroy files (unlink)
  1497.     if(cfRGetVar('destroyDeletedFiles')){
  1498.         if(is_dir($completeFilename)) return cfUnlinkDir($completeFilename);else return unlink($completeFilename);
  1499.     }
  1500.     // Send files to recycle bin
  1501.     else return customSendToRecycled($completeFilename);
  1502. }
  1503.  
  1504. /**
  1505.  * @desc return a number formated according to local settings
  1506.  *
  1507.  * @param number $num: number to format
  1508.  * @param int $decimal: number of fraction figures
  1509.  * @return string
  1510.  */
  1511. function efNumberFormat($num,$decimal=0){
  1512.     if(!isset($_ENV['locale'])){
  1513.         setlocale(LC_NUMERIC,cfCaption('_ISO_639'));
  1514.         $_ENV['locale']=localeconv();
  1515.         if(ord($_ENV['locale']['thousands_sep'])==160) $_ENV['locale']['thousands_sep']=' ';
  1516.         setlocale(LC_NUMERIC,'eng');
  1517.     }
  1518.     return number_format($num,$decimal,$_ENV['locale']['decimal_point'],$_ENV['locale']['thousands_sep']);
  1519. }
  1520.  
  1521. /**
  1522.  * @desc : return dimension of an image ($srcWidth x $srcHeight) resized to fit in $maxWidth x $maxHeight square
  1523.  *
  1524.  * @param integer $srcWidth
  1525.  * @param integer $srcHeight
  1526.  * @param integer $maxWidth
  1527.  * @param integer $maxHeight
  1528.  * @param boolean $noStretch: true not to stretch image if destination larger than source
  1529.  * @return array : output width, height
  1530.  */
  1531. function efGetOutputImageDimensions($srcWidth, $srcHeight, $maxWidth, $maxHeight=0, $noStretch=false){
  1532.     if(!$srcHeight ||!$srcWidth) return array($maxWidth,$maxHeight);
  1533.     if(!$maxWidth && !$maxHeight) $maxWidth=100;
  1534.     $tnMW=$maxWidth;if(!$tnMW) $tnMW=$maxHeight;
  1535.     $tnMH=$maxHeight;if(!$tnMH) $tnMH=$maxWidth;
  1536.     $tnRatio=$tnMW/$tnMH;$imgRatio=$srcWidth/$srcHeight;
  1537.     if($imgRatio>=$tnRatio) $tnMH=floor($tnMW/$imgRatio); else $tnMW=floor($tnMH*$imgRatio);
  1538.     if($noStretch && $tnMW>$srcWidth) return array($srcWidth,$srcHeight);
  1539.     return array(floor($tnMW),floor($tnMH));
  1540. }
  1541.  
  1542. /**
  1543.  * @desc Update preview image in image gallery explorer
  1544.  * Generate HTML page with javascript updating parent frame preview image :
  1545.  * src img with id="previewImage" is changed
  1546.  * image title with id="previewTitle" is changed
  1547.  * image file name with id="previewFileName" is changed
  1548.  * next and previous images with id "previewNext" and "previewPrevious"
  1549.  *
  1550.  * @param string $completeFilename : path and name of preview image
  1551.  * @param integer $maxWidth : max output image width (overridden by cfRGetVar('previewMaxWidth') if not cfRGetVar('previewAutoSize')
  1552.  * @param integer $maxHeight : max output image height (overridden by cfRGetVar('previewMaxHeight') if not cfRGetVar('previewAutoSize')
  1553.  */
  1554. function efUpdatePreview($completeFilename, $maxWidth=false, $maxHeight=false){
  1555.     // Check file download rights
  1556.     $completeFilename=cfCleanPathName($completeFilename);
  1557.     $passedFile=basename($completeFilename);
  1558.     if(!cfFileRights($completeFilename,'download')) exit;
  1559.  
  1560.     // Log in viewed content history
  1561.     cfLogContentAccess($completeFilename);
  1562.  
  1563.     if($maxWidth && !is_numeric($maxWidth)) exit;
  1564.     if(!$maxHeight) $maxHeight=$maxWidth*3/4;
  1565.  
  1566.     // Start output
  1567.     $js= 'with(preview){';
  1568.  
  1569.     // Image file name
  1570.     $js.='setFilename("'.cfUTF8Encode(basename($completeFilename)).'");';
  1571.  
  1572.     // Preview rotation
  1573.     $rotation=cfRGetVar('previewAngle',false,false,null);
  1574.  
  1575.     // Exif rotation
  1576.     if((cfFileExtension($completeFilename)=='jpg' || cfFileExtension($completeFilename)=='jpeg') && cfGGetVar('EXIFAutoRotation') && $rotation===null){
  1577.         if($angle=cfArrayItem(@exif_read_data($completeFilename),'Orientation')){
  1578.             if($angle==3) $rotation=180;
  1579.             if($angle==6 || $angle==7) $rotation=90;
  1580.             if($angle==5 || $angle==8) $rotation=270;
  1581.             cfRSetVar('previewAngle',$rotation);
  1582.         }
  1583.     }
  1584.  
  1585.  
  1586.     // Output image size
  1587.     if($maxWidth>0 && $maxHeight>0){
  1588.         if(cfFileExtension($completeFilename)=='itc' || cfFileExtension($completeFilename)=='itc2') $width=$height=0;
  1589.         else list($width, $height, $type, $attr) = @getimagesize($completeFilename);
  1590.         if(!isset($width)) $width=0; if(!isset($height)) $height=0;
  1591.  
  1592.         // 90░ / 270░ rotation: swap width & height
  1593.         if(cfRGetVar("previewAngle")==270 || cfRGetVar("previewAngle")==90) cfSwap($width,$height);
  1594.         // Compute
  1595.         list($w,$h)=efGetOutputImageDimensions($width, $height, $maxWidth, $maxHeight);
  1596.  
  1597.         // Stretch / don't stretch small images
  1598.         if((!cfRGetVar('stretchSmallImages')) && ($w>$width || $h>$height)) {$w=$width; $h=$height;}
  1599.  
  1600.         // Image src
  1601.         $js.='updateSrc("'.cfExtImage($completeFilename, $w, $h, true, (int)$rotation).'",'.((int)$w).','.((int)$h).');';
  1602.         //cfDbg($js);
  1603.     }
  1604.  
  1605.     // Image title
  1606.     $js.= 'setTitle("'.cfUTF8Encode(cfFileWithoutExtension(str_replace('"','',$passedFile))).'");';
  1607.  
  1608.     // Image file name
  1609.     $js.= 'filename="'.cfProtectFilename($passedFile).'";';
  1610.  
  1611.     $np=efGetNextAndPrevious($passedFile);
  1612.  
  1613.     // Next image name
  1614.     $js.= 'next="'.cfUTF8Encode($np['next']).'";';
  1615.  
  1616.     // Previous image name
  1617.     $js.= 'prev="'.cfUTF8Encode($np['previous']).'";';
  1618.  
  1619.     // Image comments
  1620.     $comments=efReadComments($completeFilename);
  1621.     $js.= 'commentsSet("'.cfUTF8Encode(str_replace('"','\\"',$comments),false,false).'");';
  1622.  
  1623.     // image current angle
  1624.     $js.= 'angle='.(int)$rotation.';';
  1625.  
  1626.     $js.='}';
  1627.  
  1628.     // Send async response
  1629.     cfAsyncHeader();
  1630.     echo cfAsyncXMLJSaction($js);
  1631.     echo cfAsyncFooter();
  1632.     exit();
  1633. }
  1634.  
  1635.  
  1636. /*
  1637. ***************************************************************************************************************************
  1638. *
  1639. * efFiles files array functions
  1640. *
  1641. ***************************************************************************************************************************
  1642. */
  1643.  
  1644. /**
  1645.  * @desc (re)init explorer data
  1646.  *
  1647.  */
  1648. function efInit(){
  1649.     // If configuration updated or resource not initalized, reset config
  1650.     if((!cfRGetVar('explorerInitialized')) || cfRGetVar('memUpdate')!=cfRGetVar('sessionUpdate')){
  1651.         cfRSetVar('treeViewAvailable',false);
  1652.         cfRInitVar('actionsPanel',true);
  1653.  
  1654.         if(cfSharedMode('list')){
  1655.             // Reset directory
  1656.             cfRSetVar('efCurrentDirectory','*resourceBasePath*');
  1657.  
  1658.             // Build filename=>"d" || "f" array
  1659.             cfRUnsetVar('sharedItems');
  1660.             $sharedItems=array();
  1661.             foreach (explode('|',cfRGetVar('sharedItems')) as $v)
  1662.             $sharedItems[$v]=((is_dir($v))?'d':'f');
  1663.             foreach ($sharedItems as $type) if($type=='d') {cfRSetVar('treeViewAvailable','mainTree');break;}
  1664.             cfRSetVar('sharedItems',$sharedItems);
  1665.             cfRSetVar('subFoldersIncluded',true);
  1666.         }
  1667.         else{
  1668.             cfRSetVar('efCurrentDirectory',cfCleanPathName(cfRGetVar('path')));
  1669.             cfRUnsetVar('subFoldersIncluded');
  1670.             if(!cfRGetVar('efCurrentDirectory')) {$errorMessageCritical=cfCaption('explorerErrorNoValidDir'); return false;}
  1671.  
  1672.             // Treeview available
  1673.             if(cfRGetVar('subFoldersIncluded')) cfRSetVar('treeViewAvailable','mainTree'); else cfRSetVar('treeViewAvailable',false);
  1674.         }
  1675.  
  1676.         // Common parameters
  1677.         cfRInitVar('filesLayout','resource'); // 'list', 'icons', 'resource'
  1678.         cfRInitVar('thumbnailsSize',240); // 0: small, 1: medium, 2: big
  1679.         cfRInitVar('thumbnailsSizeFactor',1); // 0: small, 1: medium, 2: big
  1680.  
  1681.         cfRInitVar('itemsPerPage',50); // thumbnails per page - 0: unlimited, 10, 20, 50
  1682.  
  1683.         // Photo explorer default items per page, per layout (layout 3 displays everything)
  1684.         cfRInitVar('itemsPerPageLayout1',20); // Layout 1
  1685.         cfRInitVar('itemsPerPageLayout2',50); // Layout 2
  1686.  
  1687.         // Wii: fix flash video chunk length to 4mn, as Wii freeze after 5mn
  1688.         if(cfIsWII()) cfRSetVar('flashChunkLength',120);
  1689.  
  1690.         // Browser specific parameters
  1691.         if(!cfBGetVar('download'))    {
  1692.             cfRSetVar('multipleDownloadAllowed',false);
  1693.             cfRSetVar('downloadShortcut',false);
  1694.             cfRSetVar('uploadAllowed',false);
  1695.             cfRSetVar('displayMultipleDownload',false);
  1696.         }
  1697.         cfRSetVar('explorerInitialized',true);
  1698.         cfRSetVar('sessionUpdate',cfRGetVar('memUpdate'));
  1699.     }
  1700.  
  1701.     // Define resource-vars that will be saved if user is singleUser
  1702.     cfSetSavedRVar('efCurrentDirectory','efSortBy','efSortOrder','actionsPanel','displayTransfers','treeViewDisplayed','sortField','scrollMainFileTable','displayMultipleDownload','layout','filesLayout','thumbnailsSizeFactor');
  1703. }
  1704.  
  1705. /**
  1706.  * @desc Return an array containing files and subdirectories of a given directory
  1707.  * array also contains properties of files
  1708.  *
  1709.  * @param string $dir : directory
  1710.  * @param bool $includeSubDirs : if true, include subdirectories of $dir
  1711.  * @param string $extensionFilter : array of extensions that will be listed. Files with an extension not matching those criterias are excluded
  1712.  * @param array $fileTypeFilter : array of extensions that will be listed. Files with a type not matching those criterias are excluded
  1713.  * @param bool $sort: if true, sort array using cfRGetVar('efSortBy') and cfRGetVar('efSortOrder') parameters
  1714.  * @param  array $options: extra options:
  1715.  *            'includeRights' : set this option to include file rights to file data (used not to call cfFileRights twice in explorer/std)
  1716.  *            'noExtra': set this option not to get file's extra info
  1717.  *            'iconSize': exe/ico extracted icon size (16,32)
  1718.  * @return array : array of files and subdirs (see description inside function)
  1719.  */
  1720. function efGetDirContent($dir, $includeSubDirs=true, $extensionFilter=false, $fileTypeFilter=false,$sort=false,$options=false){
  1721.     global $errorMessage;
  1722.     global $errorMessageCritical;
  1723.     // returned array :
  1724.  
  1725.     // if a critical error message has already been raised, exit
  1726.     if($errorMessageCritical) return false;
  1727.  
  1728.     // Common fields (files, dirs, drives)
  1729.     // effDir[fileNumber]['name'] : file name
  1730.     // effDir[fileNumber]['type']  : file type ('dir', 'file')
  1731.     // effDir[fileNumber]['rights']  (if options set 'includeRights') : file rights (from cfFileRights function)
  1732.  
  1733.     // Drives only fields
  1734.     // effDir[fileNumber]['freeSpace'] : file size (bytes)
  1735.     // effDir[fileNumber]['totalSpace'] : file size (bytes)
  1736.  
  1737.     // Files and dirs fields
  1738.     // effDir[fileNumber]['date'] : file last modification date
  1739.  
  1740.     //Files only fields
  1741.     // effDir[fileNumber]['size'] : file size (bytes)
  1742.     // effDir[fileNumber]['extra1'] : default extra file info displayed in std explorer
  1743.     // effDir[fileNumber]['subType']  : file type ('image', 'music', ...)
  1744.  
  1745.     $iconSize=isset($options['iconSize'])?$options['iconSize']:((efFilesListType()=='icons')?32:16);
  1746.  
  1747.     if($fileTypeFilter && !is_array($fileTypeFilter)) $fileTypeFilter=array($fileTypeFilter);
  1748.  
  1749.     // clean $dir
  1750.     $dir=cfCleanPathName($dir);
  1751.  
  1752.     // if access to $dir is not authorized to logged user
  1753.     if(!($dir) || cfFileRights($dir,'state')!='authorized') {
  1754.         // If forbidden directory, try to reset to base path (might happend when base path is changed while user is connected&browsing)
  1755.         $dir=((cfSharedMode('list'))?'*resourceBasePath*':cfRGetVar('path'));
  1756.         cfRSetVar('efCurrentDirectory',$dir);
  1757.         if(!($dir) || cfFileRights($dir,'state')!='authorized') return false;
  1758.     }
  1759.  
  1760.     // Include or not complete file rights
  1761.     if(isset($options['includeRights']) && $options['includeRights']) $includeRights=true; else $includeRights=false;
  1762.  
  1763.     $efFiles=array();
  1764.     $nbFiles=0;    $nbSubDirs=0; $n=0;
  1765.     $efFiles['dir']=$dir;
  1766.  
  1767.     // If $dir is computerRoot
  1768.     if($dir=='computerRoot'){
  1769.         // Browse drives
  1770.         for ($i=66;$i<91;$i++) {
  1771.             $driveName=chr($i).":/";
  1772.             if (is_dir($driveName)){
  1773.                 $efFiles[$nbSubDirs]=efDriveInfo($driveName);
  1774.                 $nbSubDirs++;
  1775.             }
  1776.         }
  1777.         $efFiles['nbSubDirs']=$nbSubDirs;$efFiles['nbFiles']=0;$efFiles['nbTotal']=$nbSubDirs;
  1778.         return $efFiles;
  1779.     }
  1780.     // Else, if dir is not computer root
  1781.  
  1782.     // var caching
  1783.     $folderIcon=outIcon('fi/folder');
  1784.     $fileIcons=array();
  1785.     $useFilesCache=false; // Set to true to use data/filesCache.db for file information cache
  1786.  
  1787.     if (substr($dir,-1)!="/") $dir=$dir.'/';
  1788.  
  1789.     // Look for shared files and dirs
  1790.     $files=array();
  1791.  
  1792.     if(cfSharedMode('list') && $dir=='*resourceBasePath*/'){
  1793.         foreach (cfSharedItems() as $cfn=>$type) $files[]=$cfn;
  1794.     }
  1795.     else{
  1796.         if(($handle = @opendir($dir))==false)     return false;
  1797.         while (($file = @readdir($handle))!==false) if($file !== "." && $file !== "..") $files[]=$dir.$file;
  1798.         closedir($handle);
  1799.  
  1800.         // Get files cache data if needed
  1801.         if(!@$options['noExtra'] && cfGGetVar('cacheFilesData')){
  1802.             // Create DB if inexistant
  1803.             if(!file_exists($db=cfAppDataDir().'/filesCache.db')){
  1804.                 require_once(INCLUDE_DIR.'initFunctions.php');
  1805.                 ifSetFilesCacheDB();
  1806.             }
  1807.             $db=sqlite_open($db);
  1808.             $dirNBS=substr($dir,0,strlen($dir)-1);
  1809.             if(!($dirId=sqlite_single_query('SELECT id FROM dirs WHERE path="'.$dirNBS.'"',$db))){
  1810.                 sqlite_query('INSERT INTO dirs VALUES (NULL, "'.$dirNBS.'")',$db);
  1811.                 $dirId=sqlite_last_insert_rowid($db);
  1812.             }
  1813.             $tmp=sqlite_array_query('SELECT * FROM files WHERE dirId='.$dirId,$db,SQLITE_ASSOC);
  1814.             foreach ($tmp as $k=>$v) $filesCache[$v['filename']]=array('mtime'=>$v['mtime'],'data'=>$v['data']);
  1815.             unset($tmp);
  1816.             $useFilesCache=true;
  1817.             $cacheUpdateQuery='';
  1818.         }
  1819.     }
  1820.  
  1821.     // Browse found files & dirs
  1822.     foreach ($files as $completeFilename){
  1823.         $n=$nbSubDirs+$nbFiles;
  1824.         $file=basename($completeFilename);
  1825.  
  1826.         // Get file access rights
  1827.         if($includeRights) {
  1828.             $rights=cfFileRights($completeFilename,false,false);
  1829.             $state=$rights['state'];
  1830.         }
  1831.         else $state=cfFileRights($completeFilename,'state',false);
  1832.  
  1833.         // SUBDIRECTORY
  1834.         if(is_dir($completeFilename)){
  1835.             if ($includeSubDirs && ($state=='authorized' || !cfGGetVar('generalHideUnallowedFiles'))) {
  1836.                 $efFiles[$n]=array('name'=>$file,'completeFileName'=>$file,'size'=>0,'type'=>'dir','icon'=>$folderIcon,'date'=>@filemtime($completeFilename));
  1837.                 if($includeRights) $efFiles[$n]['rights']=$rights;
  1838.                 $nbSubDirs++;
  1839.             }
  1840.         }
  1841.         //FILE
  1842.         else {
  1843.             $fileExt=strtolower(substr($file,strrpos($file,'.')+1));
  1844.             if(
  1845.             (      (!$fileTypeFilter && !$extensionFilter)
  1846.             || (is_array($fileTypeFilter) && !(in_array(efFileType($file), $fileTypeFilter)===false))
  1847.             || ($extensionFilter && !(array_search($fileExt, $extensionFilter)===false))
  1848.             )
  1849.             && ($state=='authorized' || !cfGGetVar('generalHideUnallowedFiles'))
  1850.             ){
  1851.                 // Get icon
  1852.                 if($fileExt=='exe'||$fileExt=='ico'||!array_key_exists($fileExt,$fileIcons)){
  1853.                     $fileIcons[$fileExt]=efIcon($completeFilename,isset($options['noExeIcon'])?false:'exe',$iconSize);
  1854.                 }
  1855.  
  1856.                 // Main properties
  1857.                 $size=cfFileSize($completeFilename);
  1858.                 $efFiles[$n]=array('name'=>$file,'completeFileName'=>$completeFilename,'size'=>$size,'type'=>'file','icon'=>$fileIcons[$fileExt],'date'=>@filemtime($completeFilename),'extra1'=>'');
  1859.                 if($includeRights) $efFiles[$n]['rights']=$rights;
  1860.  
  1861.                 $st=$efFiles[$n]['subType']=efFileType($file);
  1862.  
  1863.                 //Set file specific extra data
  1864.                 if(!isset($options['noExtra']) || !$options['noExtra']) {
  1865.                     $cacheNeedsUpdate=false;
  1866.                     // If file is in cache and is not outdated, use cache
  1867.                     if($useFilesCache && isset($filesCache[$file]) && $filesCache[$file]['mtime']==$efFiles[$n]['date']){
  1868.                         $efFiles[$n]+=unserialize($filesCache[$file]['data']);
  1869.                     }
  1870.                     else switch($st){// Get file type (i.e image, text, music...)
  1871.                         // image file
  1872.                         case "image":
  1873.                             if($fileExt=='itc' || $fileExt=='itc2' || $fileExt=='ico') $width=$height=0;
  1874.                             else {
  1875.                                 list($width, $height, $type, $attr) = @getimagesize($completeFilename);
  1876.                                 $extra['extra1']=$width.'x'.$height;
  1877.                                 $extra['width']=$width;
  1878.                                 $extra['height']=$height;
  1879.                                 $cacheNeedsUpdate=1;
  1880.                                 $efFiles[$n]+=$extra;
  1881.                             }
  1882.                             break;
  1883.                             // audio file
  1884.                         case "audio":
  1885.                             if(cfRGetVar('needAudioInfo')){
  1886.                                 $id3=efGetAudioInfo($completeFilename);
  1887.                                 if($id3 && isset($id3['formatedBitrate'])) $efFiles[$nbFiles+$nbSubDirs]['extra1']=$id3['formatedBitrate']; else $efFiles[$nbFiles+$nbSubDirs]['extra1']="";
  1888.                                 if(isset($id3['bitrate'])) $extra['bitrate']=$id3['bitrate'];
  1889.                                 if(isset($id3['artist'])) $extra['artist']=$id3['artist'];
  1890.                                 if(isset($id3['album'])) $extra['album']=$id3['album'];
  1891.                                 if(isset($id3['track'])) $extra['track']=$id3['track'];
  1892.                                 if(isset($id3['title'])) $extra['title']=$id3['title'];
  1893.                                 if(isset($id3['year'])) $extra['year']=$id3['year'];
  1894.                                 if(isset($id3['genre'])) $extra['genre']=$id3['genre'];
  1895.                                 $cacheNeedsUpdate=1;
  1896.                                 $efFiles[$n]+=$extra;
  1897.                             }
  1898.                             break;
  1899.                             // video file
  1900.                         case 'video':
  1901.                             // other : no extra data
  1902.                         default:
  1903.                     }
  1904.  
  1905.                     // If file info updated, queue to cache update query
  1906.                     if($useFilesCache && $cacheNeedsUpdate) $cacheUpdateQuery.="REPLACE INTO files VALUES (".$dirId.",'".sqlite_escape_string($file)."',".$efFiles[$n]["date"].",'".sqlite_escape_string(serialize($extra))."');";
  1907.                 }
  1908.                 $nbFiles++;
  1909.             }
  1910.         }
  1911.         cfPingUpdate(100);
  1912.     }
  1913.     // Update cache if needed
  1914.     if($useFilesCache){
  1915.         if($cacheUpdateQuery)    sqlite_query('BEGIN TRANSACTION;'.$cacheUpdateQuery.';COMMIT;',$db);
  1916.         sqlite_close($db);
  1917.     }
  1918.  
  1919.     $efFiles['nbSubDirs']=$nbSubDirs;$efFiles['nbFiles']=$nbFiles;$efFiles['nbTotal']=$n;
  1920.     // SORT FILES AND SUBDIRECTORIES LIST
  1921.     if($sort && cfRGetVar('efSortBy') && cfRGetVar('efSortOrder')) efDirSort($efFiles, cfRGetVar('efSortBy'), cfRGetVar('efSortOrder'));
  1922.     return $efFiles;
  1923. }
  1924.  
  1925. /**
  1926.  * @desc "sub function" of efDirSort
  1927.  *
  1928.  * @param array $a
  1929.  * @param array $b
  1930.  * @return integer -1 / 0 / +1 : result of comparison
  1931.  */
  1932. function compare($a,$b){
  1933.     global $globalSortBy, $globalSortOrder, $globalSortBy2, $globalSortOrder2;
  1934.     if (!isset($a[$globalSortBy]) || !isset($b[$globalSortBy]) || $a[$globalSortBy] == $b[$globalSortBy]) {
  1935.         if ($a[$globalSortBy2] == $b[$globalSortBy2]) return 0;
  1936.         if($globalSortOrder2=='asc') return (strtolower($a[$globalSortBy2]) < strtolower($b[$globalSortBy2])) ? -1 : 1;
  1937.         else return (strtolower($a[$globalSortBy2]) < strtolower($b[$globalSortBy2])) ? 1 : -1;
  1938.     }
  1939.     if($globalSortOrder=='asc') return (strtolower($a[$globalSortBy]) < strtolower($b[$globalSortBy])) ? -1 : 1;
  1940.     else return (strtolower($a[$globalSortBy]) < strtolower($b[$globalSortBy])) ? 1 : -1;
  1941. }
  1942.  
  1943. /**
  1944.  * @desc Sort a files Array on name, size or date
  1945.  *
  1946.  * @param array $filesArray : array of files
  1947.  * @param string $sortBy : primary field to use for sorting : 'name', 'size' or 'date'
  1948.  * @param string $sortOrder : ascending or descending sort ('asc' or 'desc')
  1949.  * @param string $sortBy2 : secundary field to use for sorting : 'name', 'size' or 'date'
  1950.  * @param string $sortOrder2 : secundary sort order ('asc' or 'desc')
  1951.  */
  1952. function efDirSort(&$filesArray, $sortBy='name', $sortOrder='asc', $sortBy2='name', $sortOrder2='asc'){
  1953.     global $globalSortBy, $globalSortOrder, $globalSortBy2, $globalSortOrder2;
  1954.     $globalSortBy="";
  1955.     $globalSortOrder="";
  1956.     $globalSortBy2='name';
  1957.     $globalSortOrder2='asc';
  1958.     global $globalSortBy, $globalSortOrder, $globalSortBy2, $globalSortOrder2;
  1959.     $globalSortBy=$sortBy; $globalSortOrder=$sortOrder; $globalSortBy2=$sortBy2; $globalSortOrder2=$sortOrder2;
  1960.     uasort($filesArray, "compare");
  1961. }
  1962.  
  1963. /**
  1964.  * @desc Get number of files in a files array (excludes drives and folders)
  1965.  *
  1966.  * @param array $filesArray : array of files
  1967.  * @return integer : number of files
  1968.  */
  1969. function efDirGetNbOfFiles($filesArray){
  1970.     if(!is_array($filesArray)) return 0;
  1971.     $nb=0;
  1972.     foreach ($filesArray as $value) if($value['type']=='file') $nb++;
  1973.     return $nb;
  1974. }
  1975.  
  1976. /**
  1977.  * @desc Get number of subDirs in a files array
  1978.  *
  1979.  * @param array $filesArray : array of files
  1980.  * @return integer : number of subdirectories
  1981.  */
  1982. function efDirGetNbOfSubDirs($filesArray){
  1983.     $nb=0;
  1984.     foreach ($filesArray as $value ) if($value['type']!='file') $nb++;
  1985.     return $nb;
  1986. }
  1987.  
  1988. /**
  1989.  * @desc return key index of $fileNumber's $fileType of $filesArray array
  1990.  *
  1991.  * @param array $filesArray
  1992.  * @param number of wanted file $fileNumber
  1993.  * @param string $fileType : type of file
  1994.  * @return string : array's key of wanted file
  1995.  */
  1996. function efDirGetKeyFromFileNumber($filesArray, $fileNumber, $fileType){
  1997.     $nb=0;
  1998.     foreach ($filesArray as $key => $value){
  1999.         if($value['type']==$fileType) if($fileNumber==$nb) return $key; else $nb++;
  2000.     }
  2001. }
  2002.  
  2003. /**
  2004.  * @desc Generate a m3u file from $completeFileNames and send it to browser
  2005.  *
  2006.  * @param string $completeFileNames : name(s) of file(s) generating playlist:
  2007.  *             $completeFileNames can be an array of file names, a single audio file name or a m3u file name
  2008.  *             exit() at the end of script
  2009.  *
  2010.  */
  2011. function efSendM3UFile($completeFileNames){
  2012.     $m3uFileContent="#EXTM3U\n";
  2013.     // if input is *playlist*.m3u (music resource internal playlist), convert it to playlist's songs array
  2014.     if($completeFileNames=="*playlist*.m3u"){
  2015.         if(cfRGetVar('shufflePlaylist')) $playlist=cfRGetVar('playlistShuffled'); else $playlist=cfRGetVar('playlist');
  2016.         foreach ($playlist as $value){
  2017.             if(cfRGetVar('outputBitRate')!='original') $externalFileName=cfExtAudio(($value['completeFileName']), "audio/".cfRGetVar('outputBitRate')."/",'absolute');
  2018.             else $externalFileName=cfExtAudio($value['completeFileName'],'','absolute');
  2019.  
  2020.             if(is_file($value['completeFileName']))    $id3=efGetAudioInfo($value['completeFileName']);
  2021.             elseif (cfRGetVar('extAccessFunction')){
  2022.                 $extAccessFunction = create_function('$completeFilename', cfRGetVar('extAccessFunction'));
  2023.                 if(($value['completeFileName']=$extAccessFunction($value['completeFileName']))) $id3=efGetAudioInfo($value['completeFileName']);
  2024.             }
  2025.  
  2026.             if(!isset($value['title'])) $value['title']=$value['name'];
  2027.             $value['label']=cfUTF8Encode($value['label']);
  2028.             if(isset($id3['playtime_seconds']))
  2029.             $m3uFileContent.="#EXTINF:".(int)$id3['playtime_seconds'].','.$value['label']."\n";
  2030.             else
  2031.             $m3uFileContent.="#EXTINF:,".$value['label']."\n";
  2032.             $m3uFileContent.=$externalFileName."\n";
  2033.         }
  2034.  
  2035.         $m3uFileName='playlist.m3u';
  2036.     }
  2037.     //
  2038.     // M3U
  2039.     // if $completeFileNames is the name of a m3u files, extract links and convert it into an array of audio file names
  2040.     //
  2041.     elseif(!is_array($completeFileNames) && cfFileExtension($completeFileNames)=='m3u'){
  2042.         $m3uFileName=$completeFileNames;
  2043.         if(($handle = fopen ($m3uFileName, "r"))){
  2044.             while (!feof ($handle)) {
  2045.                 $m3uFile = trim(fgets($handle, 4096));
  2046.                 if(substr($m3uFile,0,1)!="#"){
  2047.                     $completeFilename=cfDirName($m3uFileName).'/'.$m3uFile;
  2048.                     if(file_exists($completeFilename) &&  efFileType($completeFilename)=='audio'){
  2049.                         if(cfRGetVar('outputBitRate')!='original') $externalFileName=cfExtAudio($completeFilename, "audio/".cfRGetVar('outputBitRate')."/");
  2050.                         else $externalFileName=cfExtAudio($completeFilename);
  2051.                         $id3=efGetAudioInfo($completeFilename);
  2052.                         if(isset($id3['playtime_seconds']))
  2053.                         $m3uFileContent.="#EXTINF:".(int)$id3['playtime_seconds'].','.basename($completeFilename)."\n";
  2054.                         else
  2055.                         $m3uFileContent.="#EXTINF:,".basename($completeFilename)."\n";
  2056.                         $m3uFileContent.=cfGGetVar('hostName').$externalFileName."\n";
  2057.                     }
  2058.                 }
  2059.             }
  2060.             fclose ($handle);
  2061.         }
  2062.     }
  2063.     //
  2064.     // Single audio file name
  2065.     //
  2066.     else{
  2067.         if(cfRGetVar('outputBitRate')!='original') $externalFileName=cfExtAudio(($completeFileNames), "audio/".cfRGetVar('outputBitRate')."/",'absolute');
  2068.         else $externalFileName=cfExtAudio(($completeFileNames),'','absolute');
  2069.         $id3=efGetAudioInfo($completeFileNames);
  2070.         $m3uFileContent.="#EXTINF:".((isset($id3['playtime_seconds']))?(int)$id3['playtime_seconds']:'').','.basename($completeFileNames)."\n";
  2071.         $m3uFileContent.=$externalFileName."\n";
  2072.  
  2073.         $m3uFileName=cfFileWithoutExtension(basename($completeFileNames)).'.m3u';
  2074.     }
  2075.     // Send generated m3u file to output
  2076.     header('Content-Type:audio/x-mpegurl');
  2077.     header('Content-Description: file Transfert');
  2078.     header('Content-Disposition: attachment; filename="'.cfUTF8Encode($m3uFileName)).'"';
  2079.     header('Content-Length: '.strlen($m3uFileContent));
  2080.     header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public");
  2081.     header("Pragma:"); // Do not remove, required by IE in SSL mode
  2082.     header("Expires: 0");
  2083.     echo $m3uFileContent;
  2084.     exit();
  2085. }
  2086.  
  2087. /**
  2088.  * @desc Update $_ENV['weezoResEfFiles'] array with content of "cfRGetVar('efCurrentDirectory')" directory
  2089.  * use cfRGetVar('subFoldersIncluded') for sub directories inclusion
  2090.  * use cfRGetVar('efExtensionFilter') for filtering on files extension
  2091.  * use cfRGetVar('efFileTypeFilter') for filtering on files type
  2092.  *
  2093.  * @param  array $options: extra options:
  2094.  *            'includeRights' : set this option to include file rights to file data (used not to call cfFileRights twice in explorer/std)
  2095.  *            'noThumbnails' : set this option to explcitly not generate photo/video thumbnails
  2096.  *            'noExtra' : set this option not to get file's extra info
  2097.  *
  2098.  * @return true if OK, false if NOK. If not OK, global variable $errorMessageCritical is set
  2099.  */
  2100. function efDirUpdate($options=false){
  2101.     global $errorMessage;
  2102.     global $errorMessageCritical;
  2103.  
  2104.     unset($_ENV['weezoResEfFiles']);
  2105.     $_ENV['weezoResEfFiles']=array('nbFiles'=>0,'nbSubDirs'=>0);
  2106.  
  2107.     // Init multiple download data
  2108.     if(!is_array(cfRGetVar('mDownloadList'))) cfRSetVarArray('mDownloadList');
  2109.     if(!is_array(cfRGetVar('mDownloadTotals'))) cfRSetVar('mDownloadTotals',array(0,0));
  2110.  
  2111.     // If a critical error has been raised, don't process
  2112.     if($errorMessageCritical) return false;
  2113.  
  2114.     // (Re)set current directory if not OK
  2115.     if(!cfRGetVar('efCurrentDirectory')){
  2116.         if(cfSharedMode('list')) cfRSetVar('efCurrentDirectory','*resourceBasePath*');
  2117.         else cfRSetVar('efCurrentDirectory',cfCleanPathName(cfRGetVar('path')));
  2118.         if(!cfRGetVar('efCurrentDirectory')) {$errorMessageCritical=cfCaption('explorerErrorNoValidDir'); return false;}
  2119.     }
  2120.  
  2121.  
  2122.     /**
  2123.      * Get sorted files and subfolders array
  2124.      */
  2125.     $efFiles=efGetDirContent(cfRGetVar('efCurrentDirectory'),cfRGetVar('subFoldersIncluded'),cfRGetVar('extensionFilter'),cfRGetVar('fileTypeFilter'),true,$options);
  2126.  
  2127.     if(!$efFiles) return false;
  2128.  
  2129.     // Set thumbnails JPG quality
  2130.     $thumbnailJPGQuality=((cfRGetVar('thumbnailJPGQuality'))?cfRGetVar('thumbnailJPGQuality'):((cfGGetVar('thumbnailJPGQuality'))?cfGGetVar('thumbnailJPGQuality'):DEFAULT_JPG_QUALITY));
  2131.  
  2132.  
  2133.     // thumbnails path & size
  2134.     $thumbnailsPath=efThumbnailsPath();
  2135.     $tnS=cfRGetVar('thumbnailsSize');
  2136.  
  2137.     // Photo thumbnails
  2138.     if(cfRGetVar('photoThumbnailsNeeded') && cfRGetVar('thumbnailsSize') && !isset($options['noThumbnails'])){
  2139.         // Browse images
  2140.         $missingThumbnails=0;
  2141.  
  2142.         foreach($efFiles as $key => $value ) if($value['type']=='file' && $value['subType']=='image'){
  2143.             $fileExt=cfFileExtension($value['completeFileName']);
  2144.             // ICO files : use source as thumbnail
  2145.             if($fileExt=='ico') $efFiles[$key]['thumbnail']=$value['completeFileName'];
  2146.             // ITC/ITC2 files (apple) : generate thumbnail with PHP
  2147.             elseif($fileExt=='itc' || $fileExt=='itc2'){
  2148.                 $efFiles[$key]['thumbnail']=$thumbnailsPath.'/'.$tnS.$efFiles[$key]['name'].'.jpg';
  2149.                 if(!file_exists($efFiles[$key]['thumbnail'])) cfCreateResizedJPG($value['completeFileName'],0,0,$efFiles[$key]['thumbnail'],$tnS,$tnS);
  2150.             }
  2151.             // Other graphic formats : ask application to generate thumbnail if needed
  2152.             else $efFiles[$key]['thumbnail']=$thumbnailsPath.'/'.$tnS.$efFiles[$key]['name'].'.jpg';
  2153.  
  2154.             // Inexisting thumbnail
  2155.             if(!file_exists($efFiles[$key]['thumbnail'])){
  2156.                 // Thumbnail generation monitored: add to list processed by efInsertExplorerHeadAndBody
  2157.                 if(cfRGetVar('monitorThumbnailGen'))
  2158.                     $_ENV['thumbnailPhotoNeeded'][$value['completeFileName']]=$thumbnailsPath.'/'.$tnS.$value['name'].'.jpg';
  2159.                 // PHP-generate thumbnail
  2160.                 elseif(cfGGetVar('disableCreateJPG')){
  2161.                     cfCreateResizedJPG($value['completeFileName'],0,0,$thumbnailsPath.'/'.$tnS.$value['name'].((cfFileExtension($value['name'])=='jpg' || cfFileExtension($value['name'])=='jpeg')?'.jpg':''),cfRGetVar('thumbnailsSize'),$tnS,DEFAULT_RESIZE_METHOD,false,0,false /*cfRGetVar('cropThumbnails')*/);
  2162.                 }
  2163.                 // Generate thumbnail through createJPG
  2164.                 else $missingThumbnails++;
  2165.             }
  2166.         }
  2167.  
  2168.         // createJPG-generate thumbnails if needed
  2169.         if($missingThumbnails){
  2170.             $cl='"'.cfRGetVar('efCurrentDirectory').'" "'.$thumbnailsPath.'" '.$tnS.' '.$tnS.' images';
  2171.             /*if(cfRGetVar('cropThumbnails')) $cl.=' square 100'; else*/ $cl.=' no 100';
  2172.             $cl.=' '.$thumbnailJPGQuality;
  2173.             customExecNoFork(cfAppBinDir().'/createJPG.exe','SW_HIDE',$cl); // Generate thumbnails
  2174.         }
  2175.     }
  2176.  
  2177.  
  2178.     // Video thumbnails
  2179.     $_ENV['thumbnailVideoNeeded']=array();
  2180.     if(cfRGetVar('videoThumbnailsNeeded') && !isset($options['noThumbnails'])){
  2181.         // Browse files, check if thumbnail exists, and if it doesn't, create it
  2182.         foreach ($efFiles as $key=>$value) if(is_file($value['completeFileName']) && $value['subType']=='video'){
  2183.             $efFiles[$key]['thumbnail']=$thumbnailsPath.'/'.$tnS.$efFiles[$key]['name'].'.jpg';
  2184.             if(!file_exists($efFiles[$key]['thumbnail'])) {
  2185.                 // Generate thumbnail
  2186.                 if(!cfRGetVar('monitorThumbnailGen')){
  2187.                     efMakeVideoThumbnail(
  2188.                     $value['completeFileName'],
  2189.                     $thumbnailsPath.'/'.$tnS.$value['name'].'.jpg',
  2190.                     $tnS,
  2191.                     $tnS,
  2192.                     $thumbnailJPGQuality
  2193.                     );
  2194.                     cfPingUpdate(10); // Inform server than client is still alive
  2195.                 }
  2196.                 // Mem that thumbnail has to be generated (generation called in efInsertExplorerHeadAndBody)
  2197.                 else{
  2198.                     $_ENV['thumbnailVideoNeeded'][$value['completeFileName']]=$thumbnailsPath.'/'.$tnS.$value['name'].'.jpg';
  2199.                 }
  2200.             }
  2201.         }
  2202.     }
  2203.  
  2204.     // Store nb files & subdirs (to be used on next request by efProcessPost)
  2205.     cfRSetVar('efFilesStats',array('nbFiles'=>$efFiles['nbFiles'],'nbSubDirs'=>$efFiles['nbSubDirs']));
  2206.  
  2207.     // Store result in 'efFiles' session array
  2208.     $_ENV['weezoResEfFiles']=$efFiles;
  2209.  
  2210.     unset($efFiles);
  2211.     return true;
  2212. }
  2213.  
  2214. /**
  2215.  * @desc Return an array with same properties that array generated by efDirUpdate
  2216.  *
  2217.  * @param string $cfn: file complete filename
  2218.  * @return array
  2219.  */
  2220. function efFileProperties($cfn,$unsafeDir=true){
  2221.     $prop['name']=basename($cfn);
  2222.     $prop['completeFileName']=$cfn;
  2223.     $prop['size']=cfFileSize($cfn);
  2224.     $prop['type']=(is_file($cfn)?'file':'dir');
  2225.     $prop['icon']=efIcon($cfn,true);
  2226.     $prop['date']=@filemtime($cfn);
  2227.     $prop['rights']=cfFileRights($cfn,false,$unsafeDir);
  2228.     $prop['subType']=efFileType($cfn);
  2229.     $prop['extra1']=false;
  2230.     return $prop;
  2231. }
  2232.  
  2233. /**
  2234.  * @desc Return a label for a given directory, removing resourceBasePath, and setting caption for computerRoot
  2235.  *
  2236.  * @param string $dir
  2237.  * @return string
  2238.  */
  2239. function efDirLabel($dir=false){
  2240.     if(!$dir) $dir=cfRGetVar('efCurrentDirectory');
  2241.     if($dir=='computerRoot') return cfCaption('explorerComputerRoot');
  2242.     $dir=str_replace('*resourceBasePath*','',cfResourceRelativePath($dir));
  2243.     if(!$dir) $dir='/';
  2244.     return $dir;
  2245. }
  2246.  
  2247. /**
  2248.  * @desc return JS array item corresponding to a file description
  2249.  *
  2250.  * @param integer $id: id of item
  2251.  * @param array $value: properties of file
  2252.  * @param string $options:
  2253.  *                 'relativeDir': display file's name & path relatively to this directory, 'mediumIcon': ...,
  2254.  *                 'thumbnail'=>thumbnail width: also include thumbnails
  2255.  *                 'includeType'=>1 to include mime (sub)type
  2256.  *                 'crop'=>1 to make croped square thumbnails
  2257.  * @return string
  2258.  */
  2259. function efFilePropertiesToJSArray($id,$value,$options=false){
  2260.  
  2261.     // JS Array format :
  2262.     //
  2263.     // 00 - id,
  2264.     // 01 - "d" for directories or "f" for files,
  2265.     // 02 - name,
  2266.     // 03 - draggable (0 or 1),
  2267.     // 04 - receiver (0 or 1),
  2268.     // 05 - icon path, (for directories : 0 for folder icon, 1 for locked folder icon)
  2269.     // 06 - editable (0 or 1), (0 for directories)
  2270.     // 07 - downloadable (0 forbidden, 1 ok without shortcut, 2 ok+shortcut), (0 for directories)
  2271.     // 08 - mdownloadable (0 or 1), (0 for directories)
  2272.     // 09 - size,
  2273.     // 10 - date,
  2274.     // 11 - extra info,
  2275.     // 12 - unlinkable (0 or 1),
  2276.     // 13 - renamable (0 or 1),
  2277.     // 14 - excutable (0 or 1),
  2278.     // 15 - thumbnail URL (optional)
  2279.     // 16 - thumbnail w (optional)
  2280.     // 17 - thumbnail h (optional)
  2281.     // 18 - 1st letter of file mime (sub)type
  2282.  
  2283.     // Cache data
  2284.     static $downloadShortcut;
  2285.     static $multipleDownloadAllowed;
  2286.     static $editionAllowed;
  2287.     static $modifyAllowed;
  2288.     static $downloadShortcut;
  2289.  
  2290.     if(!isset($downloadShortcut)){
  2291.         $multipleDownloadAllowed=cfRGetVar('multipleDownloadAllowed');
  2292.         $editionAllowed=cfRGetVar('editionAllowed');
  2293.         $modifyAllowed=cfRGetVar('modifyAllowed');
  2294.         $downloadShortcut=cfRGetVar('downloadShortcut');
  2295.     }
  2296.  
  2297.     // No rights set (everything but File1 explorer): set download-only rights
  2298.     if(!isset($value['rights'])) $value['rights']=array('state'=>'authorized','download'=>1,'modify'=>0,'write'=>0,'execute'=>0);
  2299.  
  2300.     static $dateFormat=0;    if(!$dateFormat) $dateFormat=cfCaption('_DATE_FORMAT');
  2301.  
  2302.     // Set most used icons
  2303.     static $ico_noX=0; if(!$ico_noX) $ico_noX=outIcon('noX');
  2304.  
  2305.     $type=(($value['type']=='dir')?'d':'f');
  2306.     $o='['.$id.',"'.$type.'",';
  2307.     if(isset($options['relativeDir'])) {
  2308.         if($options['relativeDir']=='computerRoot') $o.='"'.str_replace('"','\\"',cfProtectFilename($value['completeFileName'])).'",';
  2309.         $o.='"'.str_replace('"','\\"',cfProtectFilename(substr($value['completeFileName'],strlen($options['relativeDir'])+1))).'",';
  2310.     }
  2311.     else $o.='"'.str_replace('"','\\"',cfProtectFilename($value['name'])).'",';
  2312.  
  2313.     // Thumbnails options
  2314.     $tnOpts=(isset($options['crop']))?array('sq'=>1):array();
  2315.  
  2316.     // Dirs
  2317.     if($type=='d'){
  2318.         // Authorized subdir
  2319.         if($value['rights']['state']=='authorized') {
  2320.             // draggable && receiver
  2321.             if($value['rights']['modify'] || ($multipleDownloadAllowed && $value['rights']['read'])){
  2322.                 if($value['rights']['write'] && $modifyAllowed) $o.='1,1,';    else $o.='1,0,';
  2323.             }
  2324.             elseif($value['rights']['write']) $o.='0,1,';
  2325.             else $o.='0,0,';
  2326.             // Icon
  2327.             $o.='0,';
  2328.         }
  2329.         else $o.='0,0,1,';
  2330.  
  2331.  
  2332.         // editable, downloadable, mdownloadable, size
  2333.         $o.='0,0,';
  2334.         if($value['rights']['download'] && $multipleDownloadAllowed) $o.='1'; else $o.='0';
  2335.  
  2336.         $o.=',"",';
  2337.         // date
  2338.         $o.="'".addslashes((($value['date']!='')?cfUTF8Encode(date($dateFormat, $value['date'])):''))."',";
  2339.         // extra info
  2340.         $o.='"",';
  2341.         // Suppress
  2342.         if($value['rights']['modify'] && $value['rights']['write']) $o.='1,'; else $o.='0,';
  2343.         // Rename
  2344.         if($value['rights']['modify']) $o.='1,'; else $o.='0,';
  2345.         // Execute
  2346.         $o.='0';
  2347.     }
  2348.     // Files
  2349.     else{
  2350.         // Draggable, receiver
  2351.         if($value['rights']['modify'] || ($multipleDownloadAllowed && $value['rights']['download'] && $downloadShortcut)) $o.='1,0,'; else $o.='0,0,';
  2352.         // View file icon
  2353.         $ico=(isset($options['mediumIcon'])&&substr($value['icon'],0,4)=='/gfx')?outIcon('fi/med/'.basename($value['icon'])):$value['icon'];
  2354.         $o.="'".addslashes($ico)."',";
  2355.  
  2356.         // edit file icon
  2357.         if($value['rights']['download'] && $value['rights']['modify'] && $editionAllowed && cfFileExtension($value['name']) && strpos(EDITABLE_FILES,';'.cfFileExtension($value['name']).';')) $o.='1,'; else $o.='0,';
  2358.         //$o.=outImage($ico_edit,false,'onclick="edit(\'id'.$i.'\');"');
  2359.  
  2360.         // Download file icon
  2361.         if($value['rights']['download']){
  2362.             if($downloadShortcut) $o.='2,'; else $o.='1,';
  2363.         }
  2364.         else $o.='0,';
  2365.  
  2366.         // Multiple download icon
  2367.         if($value['rights']['download'] && $multipleDownloadAllowed) $o.='1,'; else $o.='0,';
  2368.  
  2369.         // Size
  2370.         $o.="'".addslashes(str_replace(' ',' ',efFileSizeFormat($value['size'])))."',";
  2371.         // Date
  2372.         $o.="'".addslashes((($value['date']!='')?cfUTF8Encode(date($dateFormat, $value['date'])):''))."',";
  2373.  
  2374.         // Extra info
  2375.         $o.="'".addslashes((($value['extra1'])?cfUTF8Encode($value['extra1']):''))."',";
  2376.         // Suppress
  2377.         if($value['rights']['modify']) $o.='1,'; else $o.='0,';
  2378.         // Rename
  2379.         if($value['rights']['modify']) $o.='1,'; else $o.='0,';
  2380.         // Execute
  2381.         if($value['rights']['execute']) $o.='1'; else $o.='0';
  2382.  
  2383.         // Thumbnail
  2384.         if(isset($options['thumbnail']) && ($value['subType']=='image'||$value['subType']=='video'||($value['subType']=='audio'&&!efIsPlaylist($value['name'])))){
  2385.             $adjust=($value['subType']=='audio')?3/4:1; // Ratio applied to thumbnail
  2386.  
  2387.             /**
  2388.              * Compute thumbnail dimensions
  2389.              */
  2390.  
  2391.             // Video thumbnails: as there is no source width & height info in $value, retreive this info from generated thumbnail image
  2392.             if(!isset($options['crop']) && isset($value['thumbnail']) && !isset($value['width'])) {
  2393.                 @list($value['width'],$value['height'])=@getimagesize($value['thumbnail']);
  2394.             }
  2395.  
  2396.             // Crop & square image
  2397.             if(isset($options['crop'])) $w=$h=$options['thumbnail']*$adjust;
  2398.             // Images: use source image width & height to compute actual thumbnail ratio and size
  2399.             elseif(isset($value['width'])) list($w,$h)=cfThumbnailDimensions($value['width'],$value['height'],$options['thumbnail']*$adjust,$options['thumbnail']*3/4,true);
  2400.             // No info on source (videos only I think...)
  2401.             else {$w=$options['thumbnail']*$adjust;$h=floor(3*$options['thumbnail']/4);}
  2402.  
  2403.  
  2404.             /**
  2405.              * Insert thumbnail link and dimensions info
  2406.              */
  2407.  
  2408.             // If a thumbnail exists, base smaller thumbnail on it
  2409.             if(isset($value['thumbnail'])) $o.=',"'.cfExtImage(isset($value['thumbnail'])?$value['thumbnail']:$value['completeFileName'],$w,$h,true,0,$tnOpts).'",'.$w.','.$h;
  2410.             // Else, base thumbnail on actual file (disabled for videos as it would take too much time
  2411.             elseif ($value['subType']!='video') $o.=',"'.cfExtImage($value['completeFileName'],$w,$h,true,0,($tnOpts+(($value['subType']=='audio')?array('noDC'=>1):array()))).'",'.$w.','.$h;
  2412.         }
  2413.         else if(isset($options['thumbnail'])) $o.=',0,0,0';
  2414.         // Mime type
  2415.         if(isset($options['includeType']))    $o.=',"'.substr($value['subType'],0,1).'"';
  2416.  
  2417.     }
  2418.     return $o.']';
  2419. }
  2420.  
  2421. /**
  2422.  * @desc Return a JS array filled with files properties
  2423.  *
  2424.  * @param string $type: 'all', 'files', 'dirs'
  2425.  * @param string options: see efFilePropertiesToJSArray
  2426.  * @param array $totals: array('file'=>0,'dir'=>0,'size'=>0)
  2427.  * @return string
  2428.  */
  2429. function efFilesJSArray($type='all',$options=false,&$totals=false){
  2430.     $i=0; $totals=array('file'=>0,'dir'=>0,'size'=>0);
  2431.     if(!$_ENV['weezoResEfFiles']) return 'Array()';
  2432.  
  2433.     /*
  2434.     * SUBDIRS
  2435.     */
  2436.     $out='[';
  2437.     if($type!='files') foreach($_ENV['weezoResEfFiles'] as $key=>$value) if($value['type']=='dir'){
  2438.         $out.=(($i==0)?'':',').efFilePropertiesToJSArray($i,$value,$options);
  2439.         $i++;
  2440.     }
  2441.     $totals['dir']=$i;
  2442.  
  2443.     /*
  2444.     * FILES
  2445.     */
  2446.     $nbFiles=0;
  2447.     if(isset($options['useInterval']) && cfRGetVar('itemsPerPage')>0){
  2448.         $min=(int)cfRGetVar('thumbnailsIndex');
  2449.         $max=$min+cfRGetVar('itemsPerPage');
  2450.     }
  2451.     else {
  2452.         $min=0;$max=9999;
  2453.     }
  2454.     if($type!='dirs') if($_ENV['weezoResEfFiles']) foreach($_ENV['weezoResEfFiles'] as $key=>$value) if($value['type']=='file'){
  2455.         if($nbFiles>=$min && $nbFiles<$max){
  2456.             $out.=(($i==0)?'':',').efFilePropertiesToJSArray($i,$value,$options);
  2457.             $totals['size']+=$value['size'];
  2458.             $i++;
  2459.         }
  2460.         $nbFiles++;
  2461.     }
  2462.     $out.=']';
  2463.     $totals['files']=$i-$totals['dir'];
  2464.     return $out;
  2465. }
  2466.  
  2467. /**
  2468.  * @desc Rename $passedDir/$passedFile to $passedDir/$newName (first checks access rights)
  2469.  *
  2470.  * @param string $passedDir : current directory
  2471.  * @param string $passedFile : file to rename
  2472.  * @param string $newName : new name of file
  2473.  * @param boolean copy : copy instead of rename
  2474.  * @return string : new path & file name
  2475.  */
  2476. function efRename($passedDir,$passedFile,$newName,$copy=false){
  2477.     $source=cfCleanPathName(cfJoinPathFile($passedDir,$passedFile));
  2478.  
  2479.     if(substr($newName,0,18)!='*resourceBasePath*' && substr($newName,0,2)!='//' && substr($newName,1,1)!=':')
  2480.     $dest=cfJoinPathFile($passedDir,$newName);
  2481.     else
  2482.     $dest=$newName;
  2483.  
  2484.     if(!file_exists($source) || (!$copy && !cfFileRights($source,'modify'))) return false; //if source doesn't exist or cannot be modified
  2485.  
  2486.     if(!($destDir=cfCleanPathName(cfDirName($dest)))) return false;//if dest dir doesn't exist
  2487.     if(!cfFileRights($destDir,'write')) return false; // destination dir is protected
  2488.     $destFile=basename($dest);
  2489.  
  2490.     if($copy) return @copy($source, cfJoinPathFile($destDir,$destFile));// Do copy
  2491.     return @rename($source, cfJoinPathFile($destDir,$destFile)); // Do rename
  2492. }
  2493. function efCopy($passedDir,$passedFile,$newName){return efRename($passedDir,$passedFile,$newName,true);}
  2494.  
  2495. /**
  2496.  * @return mixed new dir if ok, false if not ok
  2497.  * @param string $dir : current dir
  2498.  * @param string $file : subdir
  2499.  * @param string $action ('goDirect' or 'go')
  2500.  * @desc changes 'efCurrentDirectory' to $dir."/".$file (first checks access rights)
  2501. */
  2502. function efChangeCurrentDir($dir, $file, $action){
  2503.     // List mode
  2504.     if(cfSharedMode('list')){
  2505.         if($action=='goDirect' && substr($file,0,1)=='/') $dir='*resourceBasePath*';
  2506.         $completeFilename=cfCleanPathName(cfJoinPathFile($dir,$file));
  2507.     }
  2508.  
  2509.     // Folder mode
  2510.     else{
  2511.         //if $action=='goDirect', check if it is relative path, and if so, modify $dir and $file so it works as a regular 'go' action
  2512.         if($action=='goDirect' && $dir!='computerRoot' && !(cfCleanPathName(cfJoinPathFile($dir,$file)))) {$dir=$file;$file=".";}
  2513.         // Action = back (previous directory)
  2514.  
  2515.         if($action=='goBack'){
  2516.             $file=cfRGetVar('efPreviousDirectories',(count(cfRGetVar('efPreviousDirectories'))-1)); $dir='computerRoot';
  2517.             cfRUnsetVar('efPreviousDirectories',count(cfRGetVar('efPreviousDirectories'))-1);
  2518.         }
  2519.         //if current dir is x:/ and $file is "..", go to computer root
  2520.         //if current dir is 'computerRoot' and $file is ".", go to computer root
  2521.         if(((strlen($dir)<=3 && $file=="..") || ($dir=='computerRoot' && $file=='.')) && cfFileRights('computerRoot','state')=='authorized'){
  2522.             $completeFilename='computerRoot';
  2523.         }
  2524.         else{
  2525.             if($dir=='computerRoot')
  2526.             $completeFilename=cfCleanPathName($file);
  2527.             else
  2528.             $completeFilename=cfCleanPathName(cfJoinPathFile($dir,$file));
  2529.         }
  2530.         // if passed dir exists && is a directory && authorized, OK
  2531.         if($completeFilename && ($completeFilename=='computerRoot' || $completeFilename=='*resourceBasePath*' || is_dir($completeFilename)) && (cfFileRights($completeFilename,'state')=='authorized')){}
  2532.         // else exit
  2533.         else return false;
  2534.     }
  2535.  
  2536.     // if directory has changed
  2537.     if(cfRGetVar('efCurrentDirectory')!=$completeFilename){
  2538.         if(!cfRGetVar('efPreviousDirectories')) cfRSetVarArray('efPreviousDirectories');
  2539.         if($action!='goBack') cfRSetVar('efPreviousDirectories',count(cfRGetVar('efPreviousDirectories')), cfRGetVar('efCurrentDirectory')); // Memorize dir in navigation history
  2540.         cfRSetVar('efCurrentDirectory',$completeFilename); //Sets new directory
  2541.     }
  2542.     return $completeFilename;
  2543. }
  2544.  
  2545. /**
  2546.  * @desc execute a file on server (can be a non-exe file)
  2547.  *
  2548.  * @param string $passedDir : path
  2549.  * @param string $passedFile : filename
  2550.  * @param string $arguments : optional arguments
  2551.  * @param bool/mixed $async: not false if async response
  2552.  */
  2553. function efExecuteFile($completeFilename,$arguments=false,$async=false){
  2554.     // if this file may not be executed
  2555.     if(!cfFileRights($completeFilename,'execute')){
  2556.         cfLog('Unauthorized execution attempt on file '.cfJoinPathFile($dir,$file),LOG_ER);
  2557.         outDisplayErrorPage(cfCaption('explorerErrorExecute'));
  2558.     }
  2559.     // Execute file
  2560.     $ext=cfFileExtension($completeFilename);
  2561.     if($ext=='exe'||$ext=='com'||$ext=='bat') customExecFork($completeFilename,'SW_SHOWNORMAL', $arguments);
  2562.     else win_shell_execute($completeFilename,'open');
  2563.     //cfServerSendCommand('execute dir="'.dirname($completeFilename).'" file="'.basename($completeFilename).'" arguments="'.$arguments.'"');
  2564.  
  2565.     // Display page
  2566.     if($async){
  2567.         cfAsyncHeader();
  2568.         die(cfAsyncFooter());
  2569.     }
  2570.     cfInsertHEAD(true);
  2571.     outShadowBefore('100%');
  2572.     echo '<div class="frame1"><div class="frame1Header">'.cfCaption('explorerExecute').'</div>';
  2573.     echo '<br/><br/><center>'.cfCaption('explorerExecuted',cfUTF8Encode(basename($completeFilename))).'</center><br/>';
  2574.     echo '<center>'.outButton(cfCaption('genClose'),'javascript:close()',outIcon('close')).'</center>';
  2575.     echo '<br/><br/>';
  2576.     echo '</div>';
  2577.     outShadowAfter();
  2578.     echo '</body></html>';
  2579.     exit;
  2580. }
  2581.  
  2582. /**
  2583.  * @desc create new folder in $dir
  2584.  *
  2585.  * @param string $dir
  2586.  * @param string $folderName
  2587.  * @return boolean : result of creation
  2588.  */
  2589. function efCreateFolder($dir,$folderName){
  2590.     $dir=cfCleanPathName($dir);
  2591.     if(!$dir || $dir=='computerRoot' || !cfFileRights($dir, 'write') || file_exists(cfJoinPathFile($dir,$folderName))) return false;
  2592.     return mkdir(cfJoinPathFile($dir,$folderName));
  2593. }
  2594.  
  2595. /**
  2596.  * @desc Async search for a file
  2597.  *
  2598.  * @param string $searchString
  2599.  */
  2600. function efSearchFile($passedDir,$searchString){
  2601.     cfAsyncHeader();
  2602.     $result=array();
  2603.     flush();
  2604.     if(cfFileRights($passedDir,'read')){
  2605.         if(strpos($searchString,'*')||strpos($searchString,'?'));else $searchString='*'.$searchString.'*';
  2606.         cfMSetVar('weezoCancel'.cfUGetVar('id').'-'.cfMGetVar('id'),1);
  2607.         wSession_write_close();
  2608.         $result=efSearchFileRec($passedDir,$searchString);
  2609.         cfMUnsetVar('weezoCancel'.cfUGetVar('id').'-'.cfMGetVar('id'),1);
  2610.     }
  2611.     if(count($result)){
  2612.         $i=0;
  2613.         $output='Array(';
  2614.         $totalSize=0;
  2615.         foreach ($result as $res) {
  2616.             $output.=(($i)?',':'').efFilePropertiesToJSArray($i++,$res,(($passedDir)?array('relativeDir'=>$passedDir):false));
  2617.             $totalSize+=$res['size'];
  2618.         }
  2619.         $output.=')';
  2620.         echo cfAsyncXMLJSaction('searchFileComplete('.$output.',"'.addslashes(efFileSizeFormat($totalSize)).'");');
  2621.     }
  2622.     else{
  2623.         echo cfAsyncXMLJSaction('searchFileComplete(false,"")');
  2624.     }
  2625.     die(cfAsyncFooter());
  2626. }
  2627.  
  2628. /**
  2629.  * Async search recursive function
  2630.  *
  2631.  * @param string $dir
  2632.  * @param string $searchString
  2633.  * @return array
  2634.  */
  2635. function efSearchFileRec($dir,$searchString){
  2636.     $return=array();
  2637.     // Non-detection of async connection aborted workaround: use a 2nd message to cancel search
  2638.     if(!cfMIssetVar('weezoCancel'.cfUGetVar('id').'-'.cfMGetVar('id'))) die();
  2639.     foreach (cfGlob($dir.'/'.$searchString) as $cfn) {
  2640.         $prop=efFileProperties($cfn,false);
  2641.         if($prop['rights']['download']) $return[]=$prop;
  2642.     }
  2643.     foreach (cfGlob($dir.'/*') as $cfn) if(is_dir($cfn)&&cfFileRights($cfn,'read')) $return+=efSearchFileRec($cfn,$searchString);
  2644.     return $return;
  2645. }
  2646.  
  2647. /**
  2648.  * @desc Cancel current search
  2649.  *
  2650.  */
  2651. function efSearchFileCancel(){
  2652.     cfMUnsetVar('weezoCancel'.cfUGetVar('id').'-'.cfMGetVar('id'));
  2653.     cfAsyncHeader();
  2654.     die(cfAsyncFooter());
  2655. }
  2656.  
  2657. /**
  2658.  * @return array of string : 'previous' and 'next' : file name of previous and next files
  2659.  * @param $fileName : filename of file to search
  2660.  * @desc return next and previous files in $_ENV['weezoResEfFiles'] array
  2661. */
  2662. function efGetNextAndPrevious($fileName){
  2663.     if(!isset($_ENV['weezoResEfFiles'])) efDirUpdate();
  2664.     $fileName=strtolower($fileName);
  2665.     $first=false;$last=false;$prev=false; $next=false; $position=0; $filePosition=false;
  2666.     foreach ($_ENV['weezoResEfFiles'] as $key => $value ) if(is_array($value) && $value['type']=='file'){
  2667.         if(strtolower($value['name'])==$fileName) $filePosition=$position;
  2668.         if($first===false) $first=$value['name'];
  2669.         if($filePosition===false) $prev=$value['name'];
  2670.         if($filePosition!==false && $filePosition!=$position && $next===false) $next=$value['name'];
  2671.         $last=$value['name'];
  2672.         $position++;
  2673.     }
  2674.     if($filePosition===false) return array('previous'=>false, 'next'=>false);
  2675.     if($prev===false) $prev=$last;
  2676.     if($next===false) $next=$first;
  2677.     return array('previous'=>$prev, 'next'=>$next);
  2678. }
  2679.  
  2680.  
  2681. /*
  2682. ***************************************************************************************************************************
  2683. *
  2684. * Explorer related HTML stuff...
  2685. *
  2686. ***************************************************************************************************************************
  2687. */
  2688.  
  2689. /**
  2690.  * @return string name of command processed, or false if no command processed
  2691.  * @desc Process commands received through comForm or HTTPXlmRequest
  2692. */
  2693. function efProcessPOST(){
  2694.     global $errorMessage;
  2695.     global $errorMessageCritical;
  2696.     global $asyncResponse;
  2697.     global $tree;
  2698.  
  2699.     // If a critical error has been raised, don't process
  2700.     if($errorMessageCritical) {if(isset($_POST['asyncRequest'])) $asyncResponse='error'; return false;}
  2701.  
  2702.     /**
  2703.      * Common explorer panels / controls vars
  2704.      */
  2705.     cfAsyncXMLChangePhpVarValue('actionsPanel'); // process hide / show right panel
  2706.     cfAsyncXMLChangePhpVarValue('displayMultipleDownload'); // process hide / show multiple download frame dynamic update
  2707.     cfAsyncXMLChangePhpVarValue(SLIDESHOW_TIMER_CONTROL_NAME,array(1,2,3,4,5,10,15,30)); // process slideshow timeout value change
  2708.  
  2709.     // If form has been submited using get method, transform into POST
  2710.     if(isset($_GET['data3'])){
  2711.         if(isset($_GET['data1'])) $_POST['data1']=$_GET['data1'];
  2712.         if(isset($_GET['data2'])) $_POST['data2']=$_GET['data2'];
  2713.         $_POST['data3']=$_GET['data3'];
  2714.         if(isset($_GET['data4'])) $_POST['data4']=$_GET['data4'];
  2715.         if(isset($_GET['data5'])) $_POST['data5']=$_GET['data5'];
  2716.     }
  2717.  
  2718.     // If no command sent, return
  2719.     if(!isset($_POST['data3'])) return;
  2720.     $action=cfUTF8Decode($_POST['data3']);
  2721.  
  2722.     if(isset($_POST['data4'])) $d4=$_POST['data4'];
  2723.     if(isset($_POST['data5'])) $d5=$_POST['data5'];
  2724.  
  2725.     // Get passed dir and file
  2726.     $passedDir=false;$passedFile=false;
  2727.     if(isset($_POST['data1'])) $passedDir=cfUnprotectFilename($d1=$_POST['data1']);
  2728.     if(isset($_POST['data2'])) $passedFile=cfUnprotectFilename($d2=$_POST['data2']);
  2729.  
  2730.     // Exception for playlist
  2731.     if($passedFile=='*playlist*.m3u') $completeFilename=$passedFile;
  2732.  
  2733.     // shared list: check passed file / folder is in list and convert to actual filename
  2734.     if(cfSharedMode('list')){
  2735.         cfDebugSingle(strtoupper($action).' Received args: dir='.$passedDir.' file='.$passedFile.' cfn=>???');
  2736.         $completeFilename='';
  2737.  
  2738.         if ($passedFile=='*playlist*.m3u'){
  2739.             $completeFilename=$passedFile;
  2740.         }
  2741.         elseif ($passedFile=='/'||$passedFile=='*resourceBasePath*'){
  2742.             $completeFilename=$passedDir='*resourceBasePath*';
  2743.             $passedFile='.';
  2744.         }
  2745.         elseif(cfCmpLeft($passedFile,'*resourceBasePath*')) { // Dir passed into file
  2746.             $completeFilename=cfSharedCompleteFilename($passedFile);
  2747.             $passedDir=cfDirName($completeFilename);
  2748.             $passedFile=cfBasename($completeFilename);
  2749.         }
  2750.         elseif($passedDir){
  2751.             $completeFilename=cfSharedCompleteFilename(cfJoinPathFile($passedDir,$passedFile));
  2752.             $passedDir=cfDirName($completeFilename);
  2753.             $passedFile=cfBasename($completeFilename);
  2754.         }
  2755.         cfDebugSingle(strtoupper($action).' Processed args: dir='.$passedDir.' file='.$passedFile.' cfn=>'.$completeFilename);
  2756.     }
  2757.     // shared folder: replace *resourceBasePath* by actual path
  2758.     else{
  2759.         // Get directory
  2760.         if(cfRGetVar('path')) $passedDir=str_replace('*resourceBasePath*',cfRGetVar('path'),$passedDir);
  2761.         // Get file
  2762.         if(cfRGetVar('path')) $passedFile=str_replace('*resourceBasePath*',cfRGetVar('path'),$passedFile);
  2763.         // Merge & clean
  2764.         $completeFilename=cfCleanPathName(cfJoinPathFile($passedDir,$passedFile));
  2765.     }
  2766.  
  2767.     // If POST request has been sent by XMLHttpRequest, inform resource that an async response is expected
  2768.     if(cfIsAsync()) $asyncResponse=$action; else $asyncResponse=false;
  2769.  
  2770.     /*
  2771.     * Common explorer actions
  2772.     */
  2773.  
  2774.     // Folder navigation
  2775.     //if authorized $passedDir/$passedFile, set  efCurrentDirectory to $passedDir/$passedFile
  2776.     if(($action=='go' || $action=='goDirect' || $action=='goBack') && $passedDir) {
  2777.         if($action=='goDirect' && substr($passedFile,0,1)=='/' && substr($passedFile,0,2)!='//') {
  2778.             $passedDir=((cfSharedMode('list'))?'*resourceBasePath*':cfRGetVar('path'));
  2779.             $passedFile=str_pad(substr($passedFile,1),1,'.');
  2780.         } // Direct access to upper dir by typping "/"
  2781.         if(!efChangeCurrentDir($passedDir, $passedFile, $action))
  2782.         $errorMessage=cfCaption('explorerErrorChangeDir');
  2783.         else{
  2784.             //reset images and subDirs arrays, reset thumbnails and preview position
  2785.             cfRSetVar('thumbnailsIndex','0');cfRSetVar('activePreview',0);
  2786.             cfRSetVar('itemsPerPagePos',0);
  2787.         }
  2788.     }
  2789.     // Tree unfold
  2790.     if($action=='treeUnfoldTo' && isset($d4) && cfRGetVar('treeViewDisplayed')){
  2791.         cfAsyncHeader();
  2792.         if(is_dir($completeFilename) && cfFileRights($completeFilename,'read')){
  2793.             echo cfAsyncXMLJSaction($tree->updateScript($completeFilename));
  2794.         }
  2795.         else{
  2796.             echo cfAsyncXMLJSaction('treeTmp = new treeNode("'.$d5.'");treeTmp.setError()');
  2797.         }
  2798.         echo cfAsyncXMLJSaction('treeProcessing=0;');
  2799.         echo cfAsyncFooter();
  2800.         //cfDbg($completeFilename.'  ---   '.$d4,1);
  2801.         exit;
  2802.     }
  2803.     // Toggle tree frame displayed / hidden
  2804.     if($action=='toggleTreeFrame'){
  2805.         cfRSetVar('treeViewDisplayed',($d4==1)?true:false);
  2806.         if(($d4==0) && cfRGetVar('layout')==0) cfRSetVar('layout',1);
  2807.         if(($d4==1) && cfRGetVar('layout')==1) cfRSetVar('layout',0);
  2808.         if(($d4==0) && cfRGetVar('layout')==2) cfRSetVar('layout',3);
  2809.         if(($d4==1) && cfRGetVar('layout')==3) cfRSetVar('layout',2);
  2810.     }
  2811.     // Change files layout
  2812.     if($action=='filesLayoutSet'&&($d4=='list'||$d4=='icons'||$d4=='resource'||$d4=='customIcons') && !cfRGetVar('filesLayoutLocked')) cfRSetVar('filesLayout',$d4);
  2813.  
  2814.     // remote download
  2815.     if(($action=='rdl')){
  2816.         if(!efRemoteDownload($passedDir, $passedFile)) {
  2817.             $errorMessage=cfCaption('explorerErrorDirectDownload');
  2818.         }
  2819.         elseif ($asyncResponse){
  2820.             cfAsyncHeader();
  2821.             echo cfAsyncXMLJSaction('if(dgi("transfersIFrame")) window.setTimeout("frames[\'transfersIFrame\'].refresh()",1000)');
  2822.             echo cfAsyncFooter();exit;
  2823.         }
  2824.     }
  2825.  
  2826.     // file download
  2827.     if(($action=='download') && ($completeFilename)){
  2828.         if(!efForceDownload($completeFilename)) $errorMessage=cfCaption('explorerErrorDownload');
  2829.     }
  2830.  
  2831.     // multiple file download functions
  2832.     if($action=='mAdd' && $passedFile && !cfRGetVar('playlistDisplayed')) efMultipleDownloadAdd($passedFile);// add file to download list (dl)
  2833.     if($action=='mSupp' && $passedFile && !cfRGetVar('playlistDisplayed')) efMultipleDownloadSupp($passedFile);// remove file from dl list
  2834.     if($action=='mSuppAll' && !cfRGetVar('playlistDisplayed')) efMultipleDownloadClear();// clear dl list
  2835.     if($action=='mAddAll' && !cfRGetVar('playlistDisplayed')) efMultipleDownloadAddAll();// add all current dir to dl list
  2836.     if($action=='mDownload') efMultipleDownloadDownload();// start zip dl
  2837.     if($action=='btDownload') efMultipleDownloadCreateTorrent();// start bittorrent dl
  2838.  
  2839.     // file VIEW
  2840.     if(($action=='view')){
  2841.         if($passedFile=='*playlist*.m3u') $completeFilename=$passedFile;
  2842.         if($completeFilename){
  2843.             require(INCLUDE_DIR.'viewFunctions.php');
  2844.             vfViewFile($completeFilename,(isset($_POST['data3']))?(cfUTF8Decode(($_POST['data3']))):(''),
  2845.             (isset($d4))?(cfUTF8Decode(($d4))) : (''),
  2846.             (isset($d5)?(cfUTF8Decode(($d5))):('')));
  2847.         }
  2848.         exit();
  2849.     }
  2850.  
  2851.     // file edit
  2852.     if(($action=='edit') || $action=='editSave' || $action=='editSaveQuit'){
  2853.         if($completeFilename){
  2854.             require(INCLUDE_DIR.'editWindow.php');
  2855.             ewDisplayEditor($completeFilename, $action, (isset($d4)?$d4:''));
  2856.         }
  2857.         exit();
  2858.     }
  2859.  
  2860.     // FILE OR FOLDER RENAME
  2861.     elseif($action=='ren'||$action=='cpy') {
  2862.         $dest=str_replace('*resourceBasePath*',cfRGetVar('path'),cfUnprotectFilename($d4));
  2863.         if(!efRename($passedDir,$passedFile,$dest,$action=='cpy')) $errorMessage=cfCaption('explorerErrorRename');
  2864.     }
  2865.  
  2866.  
  2867.     // FOLDER CREATION
  2868.     elseif(($action=='newFolder')) {if(!efCreateFolder($passedDir,$passedFile)) $errorMessage=cfCaption('explorerErrorCreateFolder');}
  2869.  
  2870.     // FILE OR FOLDER SUPPRESS
  2871.     elseif(($action=='sup')) {if(!efUnlink(cfJoinPathFile($passedDir,$passedFile))) $errorMessage=cfCaption('explorerErrorSuppress');}
  2872.  
  2873.     // FILE EXECUTION
  2874.     elseif(($action=='exe')) {efExecuteFile($completeFilename,(isset($d4))?$d4:false,(isset($d5))?$d5:false);}
  2875.  
  2876.     // FILE SEARCH
  2877.     elseif(($action=='searchFile') && isset($d4))    efSearchFile($passedDir,$d4);
  2878.     elseif(($action=='searchFileCancel'))                         efSearchFileCancel();
  2879.  
  2880.     // FILE SORT ORDER
  2881.     elseif(($action=='srt')) {
  2882.         if($_POST['data1']=='name' || $_POST['data1']=='size' || $_POST['data1']=='date') cfRSetVar('efSortBy',$_POST['data1']);
  2883.         if($_POST['data2']=='asc' || $_POST['data2']=='desc') cfRSetVar('efSortOrder',$_POST['data2']);
  2884.     }
  2885.  
  2886.     // Check if a file exists before overwritting with upload
  2887.     elseif ($action=='uploadCheckOverwrite'){
  2888.         cfAsyncHeader();
  2889.         $completeFilename=cfJoinPathFile($passedDir,basename($passedFile));
  2890.         $uploadAction='proceed';
  2891.         if(file_exists($completeFilename)){
  2892.             if(cfFileRights($completeFilename,'modify')) $uploadAction='confirm'; else $uploadAction='forbidden';
  2893.         }
  2894.         elseif (!cfFileRights($passedDir,'write') || !is_writable($passedDir)) $uploadAction='forbidden';
  2895.  
  2896.         if($uploadAction=='confirm') $caption=cfCaption('genFileAlreadyExistReplace');
  2897.         elseif($uploadAction=='forbidden') $caption=cfCaption('explorerErrorFileSend2');
  2898.         else $caption='';
  2899.         echo cfAsyncXMLJSaction('initUploadProceed("'.$uploadAction.'","'.$caption.'")');
  2900.         die(cfAsyncFooter());
  2901.     }
  2902.  
  2903.     // Display file information in tooltip
  2904.     elseif ($action=='getFileInfo'){
  2905.         cfAsyncHeader('',cfGetBrowser()!='ie');
  2906.         require(INCLUDE_DIR.'fileInfoFunctions.php');
  2907.         // Show thumbnail in tooltip
  2908.         if(isset($d4) && $d4) $getThumbnail=true; else $getThumbnail=false;
  2909.         // Show detailed info in tooltip
  2910.         if(isset($d5) && $d5=='nd') $noDetail=true; else $noDetail=false;
  2911.  
  2912.         if(cfFileRights($completeFilename,'download'))
  2913.         echo cfAsyncXMLJSaction('tooltipSetProperties('.fiPHPArrayToJSArray(fiGetInfo($completeFilename,$getThumbnail,!$noDetail)).')');
  2914.         else
  2915.         echo cfAsyncXMLJSaction('tooltipDestroy()');
  2916.         die(cfAsyncFooter());
  2917.     }
  2918.     elseif ($action=='setPos' && isset($d4)){
  2919.         if($d4=='next') cfRSetVar('itemsPerPagePos',cfRGetVar('itemsPerPagePos')+cfRGetVar('itemsPerPage'));
  2920.         elseif($d4=='prev') cfRSetVar('itemsPerPagePos',max(0,cfRGetVar('itemsPerPagePos')-cfRGetVar('itemsPerPage')));
  2921.     }
  2922.     // Change thumbnails size factor
  2923.     elseif ($action=='efTNSize' && isset($d4)){
  2924.         if(($d4==0||$d4==1||$d4==2) && !cfRGetVar('thumbnailsSizeFactorLocked')) cfRSetVar('thumbnailsSizeFactor',$d4);
  2925.     }
  2926.  
  2927.     /*
  2928.     * Photo albums related actions
  2929.     */
  2930.     // Thumbnail shift
  2931.     elseif(($action=='goThumbnail')) {
  2932.         if(0+$passedDir < 0) cfRSetVar('thumbnailsIndex','0'); else cfRSetVar('thumbnailsIndex',$passedFile);
  2933.         cfRSetVar('activePreview', cfRGetVar('thumbnailsIndex'));
  2934.     }
  2935.  
  2936.     // Thumbnails per page
  2937.     elseif($action=='changeItemsPerPage' && (is_numeric($d2) && $d2>=0 && $d2<=100)) {
  2938.         cfRSetVar('itemsPerPage', $d2);
  2939.         if($st=cfRGetVar('efFilesStats')){
  2940.             $nbFiles=$st['nbFiles'];
  2941.             cfRSetVar('thumbnailsIndex',max(0,min($nbFiles-$d2,cfRGetVar('thumbnailsIndex'))));
  2942.         }
  2943.     }
  2944.  
  2945.     // New preview
  2946.     elseif($action=='preview'){
  2947.         if(isset($d4) && isset($d5))    efUpdatePreview($completeFilename,$d4,$d5);
  2948.     }
  2949.     // New comment
  2950.     elseif ($action=='commentsSave' && isset($d4) && (cfRGetVar('commentsAllowed') && (cfUGetVar('administrator') || !cfRGetVar('administratorOnlyCanEditComments')))) {
  2951.  
  2952.         // Get comments (non-administrator comments are HTML-cleaned)
  2953.         $comments=cfUTF8Decode($d4,true,true,!cfUGetVar('administrator'),2048);
  2954.  
  2955.         // Save comments
  2956.         efWriteComments($completeFilename,$comments,false);
  2957.  
  2958.         // Javascript code to go to next image
  2959.         cfAsyncHeader();
  2960.         echo cfAsyncXMLJSaction('preview.clickNext();dgi("efCommentsTextArea").focus()').cfAsyncFooter();
  2961.         exit();
  2962.     }
  2963.     // Toggle comments edit mode
  2964.     elseif ($action=='toggleComments'){
  2965.         cfAsyncHeader();
  2966.         cfRSetVar('efEditMode',!cfRGetVar('efEditMode'));
  2967.         die(cfAsyncFooter());
  2968.     }
  2969.     // Preview image rotation
  2970.     elseif ($action=='rotate90' || $action=='rotate180' || $action=='rotate270' || $action=='rotate0'){
  2971.         cfRSetVar('previewAngle',substr($action,6));
  2972.         if(isset($d4)) efUpdatePreview($completeFilename, $d4); else efUpdatePreview($completeFilename);
  2973.     }
  2974.     /*
  2975.     * Playlist related actions
  2976.     */
  2977.  
  2978.     // Add a file to playlist
  2979.     if($action=='plAdd' && file_exists($completeFilename) && cfFileRights($completeFilename,'download')){
  2980.         // Set file properties
  2981.         $id3=efGetAudioInfo($completeFilename);
  2982.         $arr=cfRGetVar('playlist');
  2983.         $arr[]=array('completeFileName'=>$completeFilename, 'name'=>$passedFile, 'label'=>$id3['label']);
  2984.         cfRUnsetVar('playlist');
  2985.         cfRSetVar('playlist',$arr);
  2986.         cfRSetVar('noFileRefresh',true);
  2987.         efConvertPlayListToMDList();
  2988.     }
  2989.     // Move playlist item up (=to lower index) or down (=to upper index)
  2990.     if($action=='plUp' || $action=='plDown') {
  2991.         $arr=cfRGetVar('playlist');
  2992.         if(isset($arr[$d4]) && $action=='plUp' && $d4>0 || $action=='plDown' && $d4<count($arr)-1){
  2993.             cfRUnsetVar('playlist');
  2994.             cfRSetVarArray('playlist');
  2995.             $i=0;
  2996.             foreach ($arr as $value) cfRSetVar('playlist',$i++,$value);
  2997.             if($action=='plUp') {
  2998.                 cfRSetVar('playlist',$d4,$arr[$d4-1]);
  2999.                 cfRSetVar('playlist',$d4-1,$arr[$d4]);
  3000.             }
  3001.             else{
  3002.                 cfRSetVar('playlist',$d4+1,$arr[$d4]);
  3003.                 cfRSetVar('playlist',$d4,$arr[$d4+1]);
  3004.             }
  3005.             cfRSetVar('noFileRefresh',true);
  3006.             efConvertPlayListToMDList();
  3007.         }
  3008.     }
  3009.     // Clear playlist
  3010.     if($action=='mSuppAll' && cfRGetVar('playlistDisplayed')) {
  3011.         cfRUnsetVar('playlist'); cfRSetVarArray('playlist'); cfRSetVar('noFileRefresh',true);
  3012.         efConvertPlayListToMDList();
  3013.     }
  3014.     // Remove a file from playlist
  3015.     if($action=='plSupp') {
  3016.         $arr=cfRGetVar('playlist');
  3017.         if(isset($arr[$d4])) unset($arr[$d4]);
  3018.         cfRUnsetVar('playlist');
  3019.         cfRSetVarArray('playlist');
  3020.         $i=0;
  3021.         foreach ($arr as $value) cfRSetVar('playlist',$i++,$value);
  3022.         cfRSetVar('noFileRefresh',true);
  3023.         efConvertPlayListToMDList();
  3024.     }
  3025.     // Add all current dir's files to playlist
  3026.     if($action=='mAddAll' && cfFileRights($passedDir=cfRGetVar('efCurrentDirectory'),'state')=='authorized' && cfRGetVar('playlistDisplayed')){
  3027.         $arr=cfRGetVar('playlist');
  3028.  
  3029.         $af=efGetDirContent($passedDir,false,false,'audio',false);
  3030.         foreach ($af as $key=>$value) if(is_numeric($key) && cfFileExtension($value['name'])!='m3u'){
  3031.             $completeFilename=cfJoinPathFile($passedDir,$value['name']);
  3032.             $id3=efGetAudioInfo($completeFilename);
  3033.             $arr[]=array('completeFileName'=>$completeFilename, 'name'=>$passedFile, 'label'=>$id3['label']);
  3034.         }
  3035.         cfRUnsetVar('playlist');
  3036.         cfRSetVar('playlist',$arr);
  3037.         cfRSetVar('noFileRefresh',true);
  3038.         efConvertPlayListToMDList();
  3039.     }
  3040.     // Toggle shuffle playlist
  3041.     if($action=='plToggleShuffle'){
  3042.         cfAsyncHeader();
  3043.         if(isset($d4) && $d4=='ns'){
  3044.             cfRSetVar('shufflePlaylist',false);
  3045.             echo cfAsyncXMLJSaction('dgi("plShuffleBtOn").style.display="none";dgi("plShuffleBtOff").style.display="inline";');
  3046.         }
  3047.         else {
  3048.             cfRSetVar('shufflePlaylist',true);
  3049.             echo cfAsyncXMLJSaction('dgi("plShuffleBtOn").style.display="inline";dgi("plShuffleBtOff").style.display="none";');
  3050.         }
  3051.         echo cfAsyncFooter();exit;
  3052.     }
  3053.     // Other audio explorer
  3054.     if($action=='groupBy' && isset($d4)){
  3055.         if($d4=='groupAlbum') cfRSetVar('sortField','album');
  3056.         elseif($d4=='groupArtist') cfRSetVar('sortField','artist');
  3057.         elseif($d4=='groupArtistAlbum') cfRSetVar('sortField','artistAlbum');
  3058.         else cfRSetVar('sortField','no');
  3059.     }
  3060.  
  3061.     /**
  3062.  * Mobile specific actions
  3063.  */
  3064.     if($action=='setView' && isset($d4)) {
  3065.         cfRSetVar('view',substr($d4,0,100));
  3066.         cfRSetVar('itemsPerPagePos',0);
  3067.     }
  3068. }
  3069.  
  3070. /**
  3071.  * @desc Insert javascripts needed by explorers
  3072.  *
  3073.  * @return void
  3074.  */
  3075. function efInsertJScripts(){
  3076.     global $errorMessageCritical;
  3077.     // If a critical error has been raised, don't process
  3078.     if($errorMessageCritical) return false;
  3079. ?>
  3080. <script language="javascript" type="text/javascript">
  3081. <?php
  3082. // File comments vars
  3083. if(cfRGetVar('commentsAllowed') && (!cfRGetVar('administratorOnlyCanEditComments') || cfUGetVar('administrator'))){
  3084.     echo 'var editMode='.((int)cfRGetVar('efEditMode')).";\n";
  3085. }
  3086. // Image preview vars
  3087. if(cfRGetVar('previewDisplay')) {
  3088.     echo "var currentImage=".(cfRGetVar('activePreview')+0).";\n";
  3089.     echo "var slideShowActive=0;\n";
  3090.     echo "var slideShowTimer;\n";
  3091. }
  3092. // search files vars
  3093. if(cfRGetVar('searchFiles')) {
  3094.     echo 'var efSearchTitle="'.cfCaption('genFiles')."\";\n";
  3095.     echo 'var efSearchText="'.cfCaption('genSearch')."\";\n";
  3096.     echo 'var efSearchIcon="'.outIcon('search')."\";\n";
  3097.     echo 'var efSearchOkCaption="'.cfCaption('genOK')."\";\n";
  3098.     echo 'var efSearchCancelCaption="'.cfCaption('genCancel')."\";\n";
  3099. }
  3100. // All other vars needed by explorer.js functions
  3101. ?>
  3102. var slideShowInterval=<?php echo (max(1,0+cfRGetVar('slideShowInterval'))*1000); ?>;
  3103. var efCaptExplorerEnterNewName="<?php echo cfCaptionJS('explorerEnterNewName');?>";
  3104. var efCaptGenConfirmMove="<?php echo cfCaptionJS('genConfirmMove');?>";
  3105. var efCaptGenConfirmCopy="<?php echo cfCaptionJS('genConfirmCopy');?>";
  3106. var efCaptGenConfirmSuppress="<?php echo cfCaptionJS('genConfirmSuppress');?>";
  3107. var efCaptExplorerEnterFolderName="<?php echo cfCaptionJS('explorerEnterFolderName');?>";
  3108. var efCaptExplorerEnterParameters="<?php echo cfCaptionJS('explorerEnterParameters');?>";
  3109. var efCaptExplorerAudioNoSongInPlayList="<?php echo stripslashes(cfCaptionJS('explorerAudioNoSongInPlayList'));?>";
  3110.  
  3111. var efIcoUp='<?php echo str_replace("'","\\'",outImage(outIcon('up')));?>';
  3112. var efIcoDown='<?php echo str_replace("'","\\'",outImage(outIcon('down')));?>';
  3113.  
  3114. var phpRVarInlinePlayer=<?php echo (int)cfRGetVar('inlinePlayer');?>;
  3115. var efEditMode=<?php echo(cfRGetVar('efEditMode')?'1':'0');?>;
  3116. </script>
  3117. <?php
  3118. // Include explorer.js scripts
  3119. echo cfScriptLink('explorer.js');
  3120. }
  3121.  
  3122. /**
  3123.  * @desc Insert HTML <head> and <body> parts for explorers, with commands communication form and "send" dialog box
  3124.  *        or insert XML header if asynchronous response is required
  3125.  *
  3126.  * @param string $bodyExtraHTML : extra HTML code to include in <body>
  3127.  * @return void
  3128.  */
  3129. function efInsertExplorerHeadAndBody($bodyExtraHTML=false, $extraOptions=false){
  3130.     global $errorMessage;
  3131.     global $errorMessageCritical;
  3132.     global $asyncResponse;
  3133.  
  3134.     // If an asynchronous response is required, just display XML header
  3135.     if($asyncResponse) {
  3136.         cfAsyncHeader();
  3137.         if($errorMessageCritical) {echo cfAsyncXMLJSaction('alert("Error : '.addslashes($errorMessage).'")').cfAsyncFooter(); exit;}
  3138.         if($errorMessage) echo cfAsyncXMLJSaction('alert("'.addslashes($errorMessage).'")');
  3139.         // Update standardComForm 'data1' with new current directory value
  3140.         echo cfAsyncXMLJSaction('D.comForm.data1.value="'.cfUTF8Encode(cfResourceRelativePath(cfRGetVar('efCurrentDirectory'))).'"');
  3141.         return;
  3142.     }
  3143.  
  3144.     // If a critical error has been raised, display error page and exit
  3145.     if($errorMessageCritical) outDisplayErrorPage($errorMessageCritical,false,true);
  3146.  
  3147.     // Insert HTML Head stuff
  3148.     cfInsertHEAD(false);
  3149.  
  3150.     // Insert Javascripts
  3151.     efInsertJScripts();
  3152.  
  3153.     // Insert extra style
  3154.     if(isset($extraOptions['style'])) echo "\n<style type=\"text/css\">\n".$extraOptions['style']."\n</style>";
  3155.     echo "\n</head>\n";
  3156.  
  3157.     // Onload
  3158.     $onload=false;
  3159.     if($errorMessage) $onload.='alert(\''.$errorMessage.'\');';
  3160.     if(preg_match('/onload\s*=\s*"([^"]{0,})"/i',$bodyExtraHTML,$matches)){
  3161.         $bodyExtraHTML=str_replace($matches[0],'',$bodyExtraHTML);
  3162.         $onload.=$matches[1].';';
  3163.     }
  3164.     if(cfRGetVar('onload')) $onload.=(($onload)?';':'').cfRGetVar('onload');
  3165.  
  3166.     // <body>
  3167.     echo '<body style="overflow:hidden" '.
  3168.     (($bodyExtraHTML)?' '.$bodyExtraHTML:'').
  3169.     (($onload)?' onload="'.$onload.'"':'').
  3170.     ((cfGetBrowser()=='webkit')?' onselectstart="return false"':'').
  3171.     ((cfGetBrowser()=='ie'||cfGetBrowser()=='webkit')?' ondragstart="return false"':'').
  3172.     ">\n";
  3173.  
  3174.     // Video thumbnails generation & monitoring
  3175.     if(isset($_ENV['thumbnailVideoNeeded']) && count($_ENV['thumbnailVideoNeeded'])) efMakeVideoThumbnails($_ENV['thumbnailVideoNeeded']); unset($_ENV['thumbnailVideoNeeded']);
  3176.  
  3177.     // Images thumbnails generation & monitoring
  3178.     if(isset($_ENV['thumbnailPhotoNeeded']) && is_array($_ENV['thumbnailPhotoNeeded'])) efMakePhotoThumbnails($_ENV['thumbnailPhotoNeeded']); unset($_ENV['thumbnailPhotoNeeded']);
  3179.  
  3180.     // Drag'n drop scripts
  3181.     if(!isset($_ENV['noDragAndDrop'])) echo cfScriptLink('wz_dragdrop.js');
  3182.  
  3183.     // top div layer (used for fixed-width templates, and to hide entire page when displaying full-size browser)
  3184.     echo '<div id="topDiv">'."\n";
  3185.  
  3186.     // Inserts standard communication FORM
  3187.     outInsertStandardComForm($_SERVER['PHP_SELF'],cfUTF8Encode(cfResourceRelativePath(cfRGetVar('efCurrentDirectory'))));
  3188. }
  3189.  
  3190. /**
  3191.  * @desc Insert (echo) hidden field including file name,
  3192.  *
  3193.  * @param string $fileName
  3194.  * @param integer $efSeqFileNumber : sequential file number
  3195.  * @param integer $hidden: true if already hidden (no need for dn)
  3196.  */
  3197. function efOutFileTag($fileName,$sequentialIndex,$hidden=0){
  3198.     return '<p id="id'.$sequentialIndex.'"'.(($hidden)?'':' class="dn"').'>'.cfProtectFilename($fileName)."</p>\n";
  3199. }
  3200.  
  3201. /**
  3202.  * @desc Insert (echo) file checkbox for use with javascripts
  3203.  *
  3204.  * @param integer $efSeqFileNumber : associated file sequential number
  3205.  */
  3206. function efOutFileCheckBox($efSeqFileNumber){if(cfRGetVar('sendAllowed')) return '<input id="cf'.$efSeqFileNumber.'" type="checkbox" name="cb">';}
  3207.  
  3208. /**
  3209.  * @desc Return true if action panel should be displayed
  3210.  *
  3211.  * @return bool
  3212.  */
  3213. function efActionPanelDisplayed(){
  3214.     return (cfRGetVar('multipleDownloadAllowed')||cfRGetVar('uploadAllowed')||(cfRGetVar('treeViewDisplayed')));
  3215.  
  3216. }
  3217.  
  3218. /**
  3219.  * @desc Output HTML code for a foldable action panel including mdl, upload and folders tree
  3220.  *
  3221.  * @param string $postion: 'right' or 'left'
  3222.  * @param string $width: width of panel
  3223.  * @param array $options: extra options:
  3224.  *                 'shadows': true to add shadows around blocks
  3225.  */
  3226. function efActionPanel($postion,$width=false,$options=false){
  3227.     global $tree;
  3228.     if(!$width) $width='200';
  3229.     $shadows=isset($options['shadows']);
  3230.     $panelExtraHTML=isset($options['panelExtraHTML'])?$options['panelExtraHTML']:'';
  3231.  
  3232.     $icons='<div style="'.outCssOpacity(50).';margin-top:0.4em">';
  3233.     if(cfRGetVar('multipleDownloadAllowed')) $icons.=outImage(outIcon('mdl'));
  3234.     if(cfRGetVar('uploadAllowed')) $icons.=outImage(outIcon('uploadMult'));
  3235.     if(cfRGetVar('treeViewDisplayed')) $icons.=outImage(outIcon('treeView'));
  3236.     $icons.='</div>';
  3237.  
  3238.     // Toggle collapse control
  3239.     if($postion=='right') echo outCollapsableTD('actionsPanel',$postion,array('innerHTML'=>$icons,'class'=>'vBanner'));
  3240.     
  3241.     // Treeview TD
  3242.     echo '<td '.$panelExtraHTML.' style="width:'.($width+((cfGetBrowser()=='ie')?0:14)).'px;vertical-align:top;padding:0;overflow:hidden'.((cfRGetVar('actionsPanel')?'':';display:none')).'" id="actionsPanel" class="vBanner">';
  3243.  
  3244.     /*
  3245.     ***************************************************************************************************************************
  3246.     * Multiple downloads
  3247.     ***************************************************************************************************************************
  3248.     */
  3249.     if(cfRGetVar('multipleDownloadAllowed')) {
  3250.         if($shadows) outShadowBefore($width);
  3251.         echo outMultipleDownloadList('frame2',false,'vertical',false,'height:11em;margin-top:0;width:'.$width.(($shadows)?';margin-bottom:0':''),(cfGetBrowser()=='ie')?'width:'.($width-10):'');
  3252.         if($shadows) outShadowAfter();
  3253.     }
  3254.  
  3255.  
  3256.     /*
  3257.     ***************************************************************************************************************************
  3258.     * Upload file form
  3259.     ***************************************************************************************************************************
  3260.     */
  3261.     if(cfRGetVar('uploadAllowed') && cfFileRights(cfRGetVar('efCurrentDirectory'),'upload')){
  3262.         if($shadows) outShadowBefore($width);
  3263.         echo outDivFrame('frame2',false,'width:'.$width.(($shadows)?';margin-bottom:0':'')).'<div class="frame2Header">'.outImage(outIcon('upload'),false,false,'margin-right:1em; vertical-align:middle');
  3264.         if(cfRGetVar('fileTypeFilter')==array('image')) echo cfCaption('explorerUploadImage');
  3265.         else echo cfCaption('uploadBoxTitle');
  3266.         echo '</div>';
  3267.         echo outUploadForm(11,'refreshPage','enabled');
  3268.         echo "</div>\n";
  3269.         if($shadows) outShadowAfter();
  3270.     }
  3271.  
  3272.     /*
  3273.     ***************************************************************************************************************************
  3274.     * Directory browsing
  3275.     ***************************************************************************************************************************
  3276.     */
  3277.     if(cfRGetVar('treeViewDisplayed')) {
  3278.         if($shadows) outShadowBefore($width);
  3279.         if(!efFilesListIsResource()) {
  3280.             $tree->syncSelectPath=false;
  3281.             $tree->sync='async';
  3282.         }
  3283.         echo $tree->HTML('frame2',false,false,'height:100px;margin-bottom:0;width:'.$width.(($shadows)?';margin-bottom:0':''));
  3284.         if($shadows) outShadowAfter();
  3285.     }
  3286.     echo '</td>';
  3287.  
  3288.     // Toggle collapse control
  3289.     if($postion=='left')  echo outCollapsableTD('actionsPanel',$postion,array('innerHTML'=>$icons));
  3290. }
  3291.  
  3292.  
  3293.  
  3294. /*
  3295. ***************************************************************************************************************************
  3296. *
  3297. * Image preview class
  3298. *
  3299. ***************************************************************************************************************************
  3300. */
  3301.  
  3302. class efPreview{
  3303.     // See efUpdatePreview() for POST processing and async refresh
  3304.  
  3305.  
  3306.     /**
  3307.      * @desc HTML code for hidden fields needed by preview update, next and previous scripts
  3308.      *
  3309.      * @param string $previewFileName : file name of currently displayed preview
  3310.      */
  3311.     function JSDefinition(){
  3312.         $previewFileName=cfRGetVar('');
  3313.         if($previewFileName) $np=efGetNextAndPrevious($previewFileName);
  3314.         $out='var preview=new PreviewImage();';
  3315.         if(!cfRGetVar('fileViewAllowed')) $out.='preview.filename="'.cfUTF8Encode($previewFileName).'";';
  3316.         if(!cfRGetVar('fileViewAllowed')) $out.='preview.fileViewAllowed=0;';
  3317.         $out.='preview.commentsEdit='.(int)cfRGetVar('efEditMode').';';
  3318.         return $out;
  3319.     }
  3320.  
  3321.     /**
  3322.      * @desc Display viewed file title
  3323.      *
  3324.      * @param string $previewFileName : file name of currently displayed preview
  3325.      * @return string : HTML Code
  3326.      */
  3327.     function title(){
  3328.         $previewFileName=@$_ENV['weezoResEfFiles'][efDirGetKeyFromFileNumber($_ENV['weezoResEfFiles'], 0+cfRGetVar('activePreview'),'file')]['name'];
  3329.         return '<span id="previewTitle">'.cfUTF8Encode(cfFileWithoutExtension($previewFileName))."</span>\n";
  3330.     }
  3331.  
  3332.     /**
  3333.      * @desc Insert preview Image for explorer/photo resources
  3334.      *
  3335.      * @param string $previewCompleteFileName : filename of file to display
  3336.      *                 (set to false not to preload image - image will be loaded on page load)
  3337.      * @param string $autoSizeBaseWidth : width of outer frame when autosizing preview
  3338.      * @param string $extraStyle: extra style of outer frame
  3339.      *
  3340.      * @return HTML code
  3341.      */
  3342.     function image($extraStyle=''){
  3343.         // Outer frame, used as drop target, vertical centering, and actual image size for automatic size
  3344.         $out='<div id="previewOuterFrame" '.(($extraStyle)?' style='.$extraStyle.'" ':'').' onmousemove="preview.ctrlsShow()" onmouseout="preview.ctrlsMouseOut()">';
  3345.         $out.=outImage(outIcon('photoPrev'),false,'id="previewPrevBt" onclick="preview.clickPrev()"','position:absolute;top:50%;left:20px;margin-top:-32px;visibility:hidden;z-index:100');
  3346.         $out.=outImage(outIcon('photoNext'),false,'id="previewNextBt" onclick="preview.clickNext()"','position:absolute;top:50%;right:20px;margin-top:-32px;visibility:hidden;z-index:100');
  3347.         if(cfRGetVar('commentsAllowed')){
  3348.             $editMode=cfRGetVar('efEditMode');
  3349.             // Comments display frame
  3350.             $out.='<div id="efCommentsFrame" style="display:'.($editMode?'none':'block').';z-index:99;text-align:center"></div>';
  3351.             // Comments edit frame
  3352.             $out.='<div id="efCommentsForm" style="display:'.($editMode?'block':'none').'">';
  3353.             // Comments caption
  3354.             $out.='<div style="width:100%;text-align:left;color:black">'.cfCaption('genComments').'</div>';
  3355.             // Textarea
  3356.             $out.='<textarea id="efCommentsTextArea" class="input" style="height:4em;width:100%;overflow:auto" onkeydown="wl.stopPropagation(event)" onclick="wl.stopPropagation(event)"></textarea><br>';
  3357.             // Save button
  3358.             $out.=outButton(cfCaption('genSave'),'javascript:preview.commentsSave()',outIcon('save'));
  3359.             $out.="</div>\n";
  3360.         }
  3361.         $out.="</div>\n";
  3362.  
  3363.         // Add image outer frame to draggable items list
  3364.         cfDragAddItem("previewOuterFrame",'+RECEIVER_ONLY','drec.elements.previewOuterFrame.highlightFunc=function(a,b){if(b) setAlpha(a,0.5); else setAlpha(a,1);}');
  3365.  
  3366.         return $out;
  3367.     }
  3368.  
  3369.     /**
  3370.      * @desc Toggle slide show button
  3371.      * @return string : HTML Code
  3372.      */
  3373.     function toggleSlideshowBt(){
  3374.         $out = outButton(cfCaption('explorerSlideShowStart'),'javascript:preview.toggleSlideshow();',outIcon('sshow'),false,'slideShowStartButton');
  3375.         $out.= outButton(cfCaption('explorerSlideShowStop'),'javascript:preview.toggleSlideshow();',outIcon('stop'),false,'slideShowStopButton','style="display:none"');
  3376.         return $out;
  3377.     }
  3378.  
  3379.     /**
  3380.      * @desc Preview image rotation buttons
  3381.      * @param string $extraHTML : extra HTML
  3382.      * @return string : HTML Code
  3383.      */
  3384.     function rotateBts($extraHTML=false){
  3385.         if(cfRGetVar('noImageRotation')) return '';
  3386.         $out='<span '.$extraHTML.'>'.outButton(false,'javascript:preview.rotateLeft();',outIcon('rotL'),cfCaption('viewRotateLeft'),'rotateLeftBt');
  3387.         return $out.outButton(false,'javascript:preview.rotateRight()',outIcon('rotR'),cfCaption('viewRotateRight'),'rotateRightBt').'</span>';
  3388.     }
  3389.  
  3390.     /**
  3391.      * @desc Insert previous preview button
  3392.      *
  3393.      * @param boolean $showCaption : show caption in button
  3394.      * @return string : HTML Code
  3395.      */
  3396.     function previousBt($showCaption=false){
  3397.         return outButton((($showCaption)?cfCaption('explorerPrevious'):''),'javascript:preview.goPrev()',outIcon('prev'),(($showCaption)?'':cfCaption('explorerPrevious')),'prevImg');
  3398.     }
  3399.  
  3400.     /**
  3401.      * @desc Insert next preview button
  3402.      *
  3403.      * @param boolean $showCaption : show caption in button
  3404.      * @return string : HTML Code
  3405.      */
  3406.     function nextBt($showCaption=false){
  3407.         return outButton((($showCaption)?cfCaption('explorerNext'):''),'javascript:preview.goNext()',outIcon('next'),(($showCaption)?'':cfCaption('explorerNext')),'nextImg');
  3408.     }
  3409.  
  3410.     /**
  3411.      * @desc View Image button
  3412.      *
  3413.      * @param boolean $showCaption : show caption in button
  3414.      * @return string : HTML Code
  3415.      */
  3416.     function viewBt($showCaption=false){
  3417.         return outButton((($showCaption)?cfCaption('explorerClickToEnlarge'):''),'javascript:preview.view()',outIcon('fscreen'),(($showCaption)?'':cfCaption('explorerClickToEnlarge')));
  3418.     }
  3419.  
  3420.     /**
  3421.      * Code for download and zip download add
  3422.      *
  3423.      * @param bool $showCaption: true to show captions in buttons
  3424.      * @return string
  3425.      */
  3426.     function downloadShortcut($showCaption=false){
  3427.         if(!cfRGetVar('downloadShortcut')) return '';
  3428.         return outButton((($showCaption)?cfCaption('photoDownload'):''),'javascript:preview.dl()',outIcon('dl'),(($showCaption)?'':cfCaption('photoDownload')));
  3429.     }
  3430.  
  3431.     /**
  3432.      * @desc Download & zip download button
  3433.      *
  3434.      * @return string : HTML Code
  3435.      */
  3436.     function downloadBts($showCaption=false){
  3437.         $out='';
  3438.         if(cfRGetVar('downloadShortcut')) $out.=outButton('','javascript:preview.dl()',outIcon('dl'),cfCaption('photoDownload'));
  3439.         if(cfRGetVar('multipleDownloadAllowed')) $out.=outButton('','javascript:preview.mAdd()',outIcon('mdl'),cfCaption('explorerMultipleDownloadAdd'));
  3440.         return $out;
  3441.     }
  3442.  
  3443.     /**
  3444.      * @desc Toggle comments edition button
  3445.      *
  3446.       * @return string : HTML code
  3447.      */
  3448.     function editCommentsBt(){
  3449.         if(!cfRGetVar('commentsAllowed') || (cfRGetVar('administratorOnlyCanEditComments') && !cfUGetVar('administrator'))) return;
  3450.         //edit image's comments button
  3451.         if (cfRGetVar('efEditMode')) return outButton(cfCaption('explorerStopEditMode'),'javascript:preview.commentsToggle()',outIcon('editNo'),false,'editStopBt').outButton(cfCaption('explorerEditMode'),'javascript:preview.commentsToggle();',outIcon('edit'),false,'editStartBt','style="display:none"');
  3452.         // Stop edit comments button
  3453.         return outButton(cfCaption('explorerStopEditMode'),'javascript:preview.commentsToggle()',outIcon('editNo'),false,'editStopBt','style="display:none"').outButton(cfCaption('explorerEditMode'),'javascript:preview.commentsToggle();',outIcon('edit'),false,'editStartBt');
  3454.     }
  3455.  
  3456.     /**
  3457.      * @desc Add code for keyboard shortcuts
  3458.      *
  3459.      */
  3460.     function setKeyboardShortcuts($scriptTags=false){
  3461.         return outKeyHandler('D',array('37'=>'preview.clickPrev()','40'=>'preview.clickNext()','37'=>'preview.clickPrev()','34'=>'preview.clickNext()','39'=>'preview.clickNext()','32'=>'preview.clickNext()','13'=>'preview.view()','27'=>'tmp()'),$scriptTags);
  3462.     }
  3463. }
  3464.  
  3465.  
  3466. /*
  3467. ***************************************************************************************************************************
  3468. *
  3469. * list/icons files view functions
  3470. *
  3471. ***************************************************************************************************************************
  3472. */
  3473.  
  3474. /**
  3475.  * @desc Return HTMl code for files layout selection
  3476.  *
  3477.  * @return string
  3478.  */
  3479. function efFilesListSelector($options=array()){
  3480.     $out='';
  3481.     $fL=cfRGetVar('filesLayout');
  3482.  
  3483.     $capt=cfCaption('genDisplay').' - '.cfCaption('sharedFilesList');
  3484.     $out.=outButton(false,'javascript:filesLayoutSet(\'list\')',outIcon('displayList'),$capt,'filesLayout_list',false,false,$fL==='list');
  3485.  
  3486.     $capt=cfCaption('genDisplay').' - '.cfCaption('explorerIcons');
  3487.     $out.=outButton(false,'javascript:filesLayoutSet(\'icons\')',outIcon('displayIcons'),$capt,'filesLayout_icons',false,false,$fL==='icons');
  3488.  
  3489.     $capt=cfCaption('genDisplay').' - '.((isset($options['resourceCaption']))?$options['resourceCaption']:cfCaption('genThumbnails'));
  3490.     $ico=(isset($options['resourceIcon']))?$options['resourceIcon']:outIcon('displayFull');
  3491.     $out.=outButton(false,'javascript:filesLayoutSet(\'resource\')',$ico,$capt,'filesLayout_resource',false,false,$fL==='resource');
  3492.     return $out;
  3493. }
  3494.  
  3495. /**
  3496.  * @desc Display list or icons files layout
  3497.  * @param nodeId: id of node to insert in, or false to document write
  3498.  * @param options:
  3499.  *             'commitDraw':false=no (done by resource), true=yes, 'onload'=body.onload
  3500.  *             'noScriptTag':true not to include <script> in sync
  3501.  *             'thumbnails':integer>0 to inclue thumbnails of given max width
  3502.  *             'crop':integer>0 to square thumbnails by croping them
  3503.  *             'resourceLayout':'useInterval' || 'all' : set to indicate resource uses this function to display items
  3504.  *                 (all=all items displayed, 'useInterval': use thumbnailIndex and itemsPerPage resource-values
  3505.  *
  3506.  */
  3507. function efFilesList($nodeId=false,$options=array()){
  3508.     if(efFilesListIsResource() && !cfRGetVar('resourceLayout')) return;
  3509.  
  3510.     // Default options
  3511.     $options=$options+array('commitDraw'=>true,'dir'=>false);
  3512.  
  3513.     // Set thumbnail size
  3514.     $tnw=efThumbnailsMaxWidth();
  3515.  
  3516.     // Sync display: insert required vars
  3517.     if(!cfIsAsync()){
  3518.         if(!isset($options['noScriptTag'])) {?><script type="text/javascript"><?php }
  3519.         ?>
  3520.         var filesListDisplayed="<?php echo efFilesListType();?>";
  3521.         var thumbnailsSizeFactor=<?php echo (int)cfRGetVar('thumbnailsSizeFactor');?>;
  3522.         var efCaptView="<?php echo stripslashes(cfCaptionJS('genView'));?>";
  3523.         var efCaptPlay="<?php echo stripslashes(cfCaptionJS('explorerAudioPlay'));?>";
  3524.         var efCaptRen="<?php echo stripslashes(cfCaptionJS('explorerRename'));?>";
  3525.         var efCaptEdit="<?php echo stripslashes(cfCaptionJS('genEdit'));?>";
  3526.         var efCaptDl="<?php echo stripslashes(cfCaptionJS('genDownload'));?>";
  3527.         var efCaptMAdd="<?php echo stripslashes(cfCaptionJS('explorerMultipleDownloadAdd'));?>";
  3528.         var efCaptSup="<?php echo stripslashes(cfCaptionJS('genDelete'));?>";
  3529.         var efCaptExe="<?php echo stripslashes(cfCaptionJS('explorerExecute'));?>";
  3530.         var efCaptOpen="<?php echo stripslashes(cfCaptionJS('genOpen'));?>";
  3531.         var efCaptNoFile="<?php echo stripslashes(cfCaptionJS('explorerEmptyDir'));?>";
  3532.  
  3533.         var efIcoDl="<?php echo outIcon('dl2');?>";
  3534.         var efIcoView="<?php echo outIcon('view');?>";
  3535.         var efIcoPlay="<?php echo outIcon('play');?>";
  3536.         var efIcoSup="<?php echo outIcon('del');?>";
  3537.         var efIcoMAdd="<?php echo outIcon('mdl');?>";
  3538.         var efIcoRen="<?php echo outIcon('ren');?>";
  3539.         var efIcoEdit="<?php echo outIcon('edit');?>";
  3540.         var efIcoExe="<?php echo outIcon('exe');?>";
  3541.  
  3542.         var efOverMus="<?php echo outIcon('overMus');?>";
  3543.         var efOverVid="<?php echo outIcon('overVid');?>"
  3544.         var efFolderIcon="<?php echo outIcon('fi/folder');?>";
  3545.         var efFolderIconM="<?php echo outIcon('fi/med/folder');?>";
  3546.         function onrightclick(e){return fL.onrightclick(e);}
  3547.         <?php
  3548. }
  3549.  
  3550.     $nb=0;
  3551.     $drag=1;
  3552.  
  3553.     // Set JS Array options
  3554.     $efFilesJSArrayOptions=array();
  3555.     if(isset($options['thumbnails'])) $efFilesJSArrayOptions+=array('thumbnail'=>$options['thumbnails']); // Include URL to thumbnail (value = thumbnails width)
  3556.     if(isset($options['crop'])) $efFilesJSArrayOptions+=array('crop'=>$options['crop']); // Crop thubnails to square them
  3557.     if(cfRGetVar('filesLayout')=='icons') $efFilesJSArrayOptions+=array('mediumIcon'=>1,'thumbnail'=>$tnw); // Include
  3558.     if(efFilesListIsResource()||efFilesListType()=='customIcons') $efFilesJSArrayOptions+=array('thumbnail'=>$tnw);
  3559.  
  3560.     if(/*efFilesListIsResource() && */cfRGetVar('resourceLayout')=='useInterval') $efFilesJSArrayOptions+=array('useInterval'=>1);
  3561.  
  3562.     // Multimedia resource: include mime (sub)type in array to separate file types
  3563.     if(is_array(cfRGetVar('fileTypeFilter')) && count(cfRGetVar('fileTypeFilter'))>1) $efFilesJSArrayOptions+=array('includeType'=>1);
  3564.  
  3565.     // Get JS array containing files properties
  3566.     $files=efFilesJSArray(($options['dir'])?'all':'files',$efFilesJSArrayOptions);
  3567.  
  3568.     // Async update files list
  3569.     if(cfIsAsync()) {
  3570.         echo cfAsyncXMLJSaction('filesListDisplayed="'.efFilesListType().'";thumbnailsSizeFactor='.(int)cfRGetVar('thumbnailsSizeFactor'));
  3571.         echo cfAsyncXMLJSaction('fL=new FilesList('.$files.',"'.cfRGetVar('filesLayout').'","'.$nodeId.'",'.$tnw.',"'.cfUTF8Encode(cfResourceRelativePath(cfRGetVar('efCurrentDirectory'))).'");fL.draw()');
  3572.     }
  3573.     // 1st sync draw
  3574.     else{
  3575.         echo 'var fL=new FilesList('.$files.',"'.cfRGetVar('filesLayout').'","'.$nodeId.'",'.$tnw.',"'.cfUTF8Encode(cfResourceRelativePath(cfRGetVar('efCurrentDirectory'))).'");';
  3576.         if($options['commitDraw']==='onload' && $nodeId) echo 'connect(D.body,"load",function(e){fL.draw()}, true);';
  3577.         elseif($options['commitDraw']) echo 'fL.draw();';
  3578.  
  3579.         if(!isset($options['noScriptTag'])) echo '</script>';
  3580.     }
  3581. }
  3582.  
  3583. /**
  3584.  * @desc Return true if resource specific layout is displayed
  3585.  *
  3586.  * @return bool
  3587.  */
  3588. function efFilesListIsResource(){return cfRGetVar('filesLayout')=='resource';}
  3589.  
  3590. /**
  3591.  * @desc Return files layout type
  3592.  *
  3593.  * @return string: list, icons, resource
  3594.  */
  3595. function efFilesListType(){return cfRGetVar('filesLayout');}
  3596.  
  3597. /**
  3598.  * @desc Async update files list/icons display
  3599.  *
  3600.  */
  3601. function efFilesListAsyncUpdate(){
  3602.     if((efFilesListIsResource()&&!cfRGetVar('resourceLayout')) || !cfIsAsync() || (!isset($_POST['data3']) && !isset($_POST['setCombinedLayout']))) return;
  3603.  
  3604.     $action=isset($_POST['data3'])?$_POST['data3']:'setCombinedLayout';
  3605.  
  3606.     // Check if command is a supported asynchronous command
  3607.     $asyncUpdateCommands=cfArrayValuesToKeys(array('goDirect','filesLayoutSet','srt','efTNSize','goThumbnail','changeItemsPerPage','setCombinedLayout'));
  3608.     if(isset($asyncUpdateCommands[$action])){
  3609.         cfAsyncHeader();
  3610.         if($action=='goDirect'){
  3611.             // Video thumbnails generation & monitoring
  3612.             if(isset($_ENV['thumbnailVideoNeeded']) && count($_ENV['thumbnailVideoNeeded'])) efMakeVideoThumbnails($_ENV['thumbnailVideoNeeded']);
  3613.  
  3614.             // Images thumbnails generation & monitoring
  3615.             if(isset($_ENV['thumbnailPhotoNeeded']) && is_array($_ENV['thumbnailPhotoNeeded'])) efMakePhotoThumbnails($_ENV['thumbnailPhotoNeeded']);
  3616.         }
  3617.  
  3618.         // Update client-side thumbnails size
  3619.         if($action=='efTNSize') echo cfAsyncXMLJSaction('tnWidth='.efThumbnailsMaxWidth());
  3620.  
  3621.         // Async update tree
  3622.         if(($action=='goDirect'||$action=='srt') && cfRGetVar('treeViewDisplayed')) {
  3623.             global $tree;
  3624.             echo cfAsyncXMLJSaction('D.comForm.data1.value="'.cfUTF8Encode(cfResourceRelativePath(cfRGetVar('efCurrentDirectory'))).'"');
  3625.             echo cfAsyncXMLJSaction($tree->updateAndSelectScript(cfRGetVar('efCurrentDirectory')));
  3626.         }
  3627.  
  3628.         // Async update view (if not explicitely not-requested by JS)
  3629.         if(!@$_POST['filesListNoUpdate']){
  3630.             $options=cfRGetVar('cropThumbnails')?array('crop'=>cfRGetVar('cropThumbnails')):array(); // crop thumbnails
  3631.             /**
  3632.              * Do update file list !
  3633.              */
  3634.             efFilesList("noFileDiv",$options);
  3635.         }
  3636.  
  3637.  
  3638.         // Remove wait mask
  3639.         echo cfAsyncXMLJSaction('asyncSetPI(0)');
  3640.  
  3641.         // Refresh thumbnail interval selection box
  3642.         if($action=='changeItemsPerPage' || $action=='goThumbnail' || $action=='goDirect') echo outExplorerThumbnailsSelector(1,true);
  3643.  
  3644.         die(cfAsyncFooter());
  3645.     }
  3646. }
  3647. ?>